Start a local directory site you own, with no platform fee. Draft wording
One Node command turns your list of checked shops into plain web pages. Draft wording
For one person starting a small local directory: one kind of business, in one or a few cities. You’ll run one Node command and upload a folder of files. You find and check every listing yourself.
This template is not available yet. It is planned, and nothing can be bought here today. Draft wording
Planned price: $49, one-time download. Draft wording
Why the button is off: the download package hasn’t been made yet, and no payment is set up. Nothing on this site asks for card details.
If the template isn't right for you, ask within 14 days of buying and we'll refund the full $49. No questions asked. Draft wording
There’s no way to reach us about a refund yet; a contact address will be posted before anything is sold.
What the build does
This is what GadgetRental’s generator does today. The download is planned to be this same code. Each point below was checked against the code on November 10, 2026.
-
One command, no packages
node build/generate.mjsreads your listings from one data file and writes every page as plain HTML. It uses only what ships with Node.js: there is nonpm installstep and no framework. -
Thin pages are held back by rules in the code
A city gets its own page only once it has 10 checked listings. Inside a published city, a city × category page appears at 3 checked listings, and search engines may index it only at 5 or more; with 3–4 it is marked
noindex,follow. City pages list checked listings only. -
Every listing shows the date you checked it
A checked listing carries the line “Checked against the shop’s own website on <date>.” A listing you haven’t checked says “Not re-checked yet.” and its page is
noindex,follow. The build stops with an error if a listing has a checked date but no source links. -
Structured data only from what the page shows
Checked listing pages get
LocalBusinessJSON-LD built from the visible fields: name, description, website, and phone, email and address when the listing shows them. City × category pages get anItemList. No ratings, no reviews, no prices. -
Free listings, and a flat-fee Featured spot that is always labeled
Every listing is free. A Featured listing is labeled “Featured”, comes first in its category, and its website link gets
rel="sponsored". The pages include a Free vs Featured table with no booking cut, and the build refuses to mark an unchecked listing as Featured. The Feature button is switched off, because no payment system is included: you would add your own. -
A sitemap with real dates
The sitemap lists only the pages that may be indexed, hub pages first. Each listing page’s
lastmodis the date you checked it; a city or category page uses the newest checked date among its listings. -
One switch for a private preview
While
STAGING = true, every page carries anoindex,nofollowtag. The included_headersfile sends the same as a header, plus a strict content policy that blocks outside scripts and form posts.robots.txtallows crawling, so search engines can see the noindex. -
The build checks your data before it writes anything
It stops on an unknown field, a missing name or category, a duplicate slug, a phone number not written like 555-555-0100, or a page title over 60 characters.
-
A record of every claim and every indexable page
Each build also writes
CLAIMS.json(every listing fact, with its source links and checked date),INDEXABLE-PAGES.md(which pages can be indexed, and why the others can’t) and a short build report. These sit beside the site, not in it. -
Page checks in a real browser
qa/check.mjsopens every page in headless Google Chrome at 360, 390 and 1440 pixels wide and fails on sideways scrolling, tap targets under 44×44 pixels, or a missing noindex. You need Chrome installed; nothing is downloaded.
Not built yet: letting a business claim its own listing. The code shows a “Claim it” button, switched off.
One listing record
The field names are the real ones from GadgetRental’s data file. Every value is made up.
Example record — fictional shop
{
"name": "Example Lens Loft",
"slug": "example-lens-loft",
"metro": "your-city",
"neighborhood": "Old Town",
"categories": [
"camera-lens"
],
"rents": [
"cinema cameras",
"lenses",
"lighting kits"
],
"pickup_delivery": "In-store pickup; delivery available",
"hours": "Mon–Fri 9am–5pm",
"phone": "555-555-0100",
"email": "rentals@example.com",
"website": "https://example.com/",
"address": "100 Example Street, Sampletown",
"blurb": "A made-up shop that rents cameras, lenses and lighting kits.",
"source_urls": [
"https://example.com/rentals"
],
"verified_date": "2026-11-07",
"featured": false
}
name(required)*- Business name as shown on its own website.
slug(required)*- Web address part for the listing page, lowercase with dashes. Must be unique.
metro(required)*- Which of your cities it belongs to.
neighborhood- Area or town, only if the business states it.
categories(required)*- One or more of your category keys. The first one is its main category.
rents- Short list of what the business says it offers.
pickup_delivery- Pickup or delivery, only as the business states it.
hours- Opening hours, copied as published.
phone- Public business number, written 555-555-0100.
email- Public business email, only if shown on its site.
website- Its own website, starting with https://.
address- Street address, only if published.
blurb(required)*- One plain, factual sentence.
source_urls- The pages you read to check the facts. Needed for a checked listing.
verified_date- The day you checked it, written YYYY-MM-DD. Empty means not checked.
featured- true or false. Can only be true on a checked listing, once you have turned payments on.
* Required: name, slug, metro, categories, blurb. GadgetRental’s file also allows 2 bookkeeping fields used only by its own earlier version; they’re planned to be left out of the template.
What’s in the download
Planned contents Not packaged yet. These files exist today in GadgetRental’s build.
Planned contents
directory-template/
├── APPROVED-COPY.md
├── build/
│ ├── generate.mjs
│ ├── data/
│ │ └── shops.json
│ ├── research/
│ │ └── SCHEMA.md
│ ├── templates/
│ │ ├── site.css
│ │ ├── favicon.svg
│ │ └── _headers
│ └── tools/
│ └── verify.mjs
└── qa/
└── check.mjs
APPROVED-COPY.md- Your site’s own wording for prices, terms and the footer. The build prints each line word for word.
build/generate.mjs- The generator. Your city list, category list, site name and web address are set near the top of this file.
build/data/shops.json- Your listings, one record per business. Planned to ship empty.
build/research/SCHEMA.md- How to fill in one listing record when you research a business.
build/templates/- The stylesheet, site icon and preview headers.
build/tools/verify.mjs- Link, sitemap and layout checks. Written for an earlier GadgetRental build; planned to be updated.
qa/check.mjs- The browser page checks described above.
Planned to be taken out: GadgetRental’s listings, its Texas city and category lists, its name and logo, and two one-off tools it used to import its earlier version.
Who it’s for
A good fit if you want to start a small directory of local businesses, on the model of free basic listings plus a labeled, flat-fee Featured spot with no cut of anyone’s sales. You’re fine running node build/generate.mjs in a terminal and putting the output folder on a static web host.
Not a fit if you want a site builder you click through, a WordPress theme, or a directory that comes with listings or visitors.
What it is not
- No hosting. You put the files on a host you choose.
- No data. It ships with no listings. You research and check each one.
- No visitors. A new directory starts with no traffic.
- No booking or payments. The Featured button is switched off until you add your own payment setup.
- No accounts or logins. There is no admin screen; you edit a data file.
- No plugins to update. It is a few plain files and Node.js.
What’s the catch?
The catch: it's code, not a business. You bring the listings, check each one yourself, and host the files. Draft wording
Most of the work in a directory is finding businesses and checking each one against its own website. The template makes the pages; it doesn’t do that work. And today it can’t be bought at all: it is planned, not packaged.
Where the code comes from
The template is planned to be the same code that builds GadgetRental, a preview directory of Texas gadget-rental shops that is not public yet. GadgetRental isn’t public and has no paying listings, so there are no results to report, and this page claims none.
Questions can’t be sent yet. When they can, it will be through the March River Group contact section, shown switched off in its preview: March River Group contact section: preview (test copy, not live)
Price
One product, one planned price.
This template is not available yet. It is planned, and nothing can be bought here today. Draft wording
Planned price: $49, one-time download. Draft wording
Why the button is off: the download package hasn’t been made yet, and no payment is set up. Nothing on this site asks for card details.
If the template isn't right for you, ask within 14 days of buying and we'll refund the full $49. No questions asked. Draft wording
There’s no way to reach us about a refund yet; a contact address will be posted before anything is sold.
- Is it a subscription?
- No. It is planned as a one-time download.
- What do I need?
- A computer with Node.js. The browser checks also need Google Chrome, and Node 22 or newer for its built-in WebSocket.
- Where can I host the site?
- Any host that serves static files. The included
_headersfile uses the Cloudflare Pages format. - Does it only work for rental shops?
- The fields were written for local shops. Your own categories and cities are set in
generate.mjs.