# BestWNC: I built a WNC directory that returns null instead of fake analytics

Source: https://www.michaelchurley.com/blog/bestwnc-honest-analytics-local-directory  
Published: 2026-09-08  
Author: Michael C. Hurley  
Tags: bestwnc, local-directory, western-north-carolina, asheville, nextjs, convex, stripe, clerk, martech, analytics

![BestWNC homepage. Find the places that make Western North Carolina feel local](screenshots/home.png)

## Who

I live in the Blue Ridge ops lane. Locals need a directory that feels like a map, not a lead-gen trap. Owners need a page they can claim without a sales call. Operators need dashboards that do not invent click-through rates.

BestWNC is for people hunting restaurants, coffee, contractors, wellness, and shops from Asheville to Boone, and for the owners of those places who will list free, claim if we already seeded them, and upgrade only when reach matters.

If you build MarTech, local SEO products, or Stripe-backed owner tools, this post is field notes.

## What

I shipped a local business directory for Western North Carolina.

Stack on the box: **Next.js 16.2.6**, React 19, **Convex**, **Clerk**, **Stripe**, PostHog, Sentry, Resend, Tailwind v4, Bun, Phosphor icons, Vercel. Repo is private under `HurleyUS/bestwnc.com`. Site is public at [bestwnc.com](https://www.bestwnc.com/).

![Owners lander. Add or claim your BestWNC page in minutes](screenshots/owners.png)

Listings start free. Paid plans live in code in `lib/billing.ts`, not as a fragile Stripe Dashboard catalog:

- **Unlimited**: $10/mo or $80/yr. photos, video, posts, events, widgets, social links, contact, messaging
- **Featured**: $50/mo or $480/yr. Unlimited plus priority / pinned placement
- **Max**: $100/mo or $960/yr. Featured plus ad credits and the top tooling tier

Manual add-ons stay manual until fulfilled: Online Presence Analysis $8, Vetted Badge $80, Listing Sync $480. Dynamic checkout builds the price at session time.

Seed data is 101 real WNC businesses. Asheville-heavy, plus Waynesville, Brevard, Hendersonville, Black Mountain, and the rest of the corridor. Claim if we already have you. Add if we do not.

The part that matters this week: **analytics honesty**. Owner analytics used to look busier than the measurement layer could defend. On September 8 I changed the API and UI so recorded cumulative views, review count, and average rating stay; period views, clicks, conversion rates, and weekly series return **`null`** with an explicit `availability` object. README says the same thing out loud. Cumulative views include repeat, owner, and bot traffic. they are not unique visitors. `null` is the product.

Same two days: ownership claims and billing hardened, unsupported sales claims stripped from marketing surfaces, Stripe webhooks allowed through session middleware when signed, and honeypot fields on every public contact / newsletter form because spam was flooding Advertising and General Inquiry. Fill the hidden field and you get silent success, no email, no lead row.

![Owner plans. Free, Unlimited, Featured](screenshots/pricing.png)

## Where

It runs on Vercel against Convex. Auth is Clerk. Money is Stripe. Mail is Resend. Errors go to Sentry. Product events go to PostHog.

Surfaces that matter:

- Public discovery: explore, categories, cities, top-rated, trending, search, business pages
- Owner funnel: `/owners`, `/claim`, `/add-business`, dashboard edit / photos / reviews / analytics / upgrade
- Pricing: `/pricing` with the plan cards that match `PLAN_DEFINITIONS`

Audience sits in Western North Carolina and with builders who ship local directories instead of another generic "AI growth" wrapper.

![Explore. directory discovery surface](screenshots/explore.png)

## When

**2026-01-08.** Init. Next.js + Convex + Tailwind. Directory MVP the same day.

**January–February.** Categories, seed scripts, Mountain Modern redesign, mobile nav, instant listing (no review queue), Sentry, claim + email verification, PostHog, Schema.org, PWA, design variant lab, Phosphor icons, Stripe checkout/portal/webhook, **101 real WNC businesses**, photo upload via Convex storage, owner dashboard, admin moderation queue.

**March.** Launch-week security and reliability. Env validation that fails fast. Stripe monetization sprint. Dynamic pricing documented. Revenue-ready checklist. Owner plans, billing roles, social tables and signed-in pages.

**April–May.** Listing boosts on the owner dashboard. Real PostHog wiring passes. Blacksmith CI gates. Production deploy prep. Robots set to index, follow.

**2026-09-07.** PR #109. secure ownership claims and billing; remove unsupported sales claims; keep purchased manual services pending until fulfillment.

**2026-09-08.** PR #110. report only recorded business analytics (`null` where unmeasured). PR #111. honeypot fields on public contact forms. HEAD `ae65364`. Two hundred sixty-one commits on `main`.

That is the clock from empty repo to an honest owner dashboard.

![About. BestWNC product story surface](screenshots/about.png)

## Why

Directories lie by default. Fake weekly charts. Fake conversion. Fake "impressions" that never existed as rows.

I refused that for BestWNC. If the counter is cumulative and polluted by owners and crawlers, say so. If period CTR is not instrumented, return `null`, not zero dressed as insight.

I also refused a soft claim path and a spam inbox. Claims require verified identity. Billing routes have security tests. Inquiry forms fail closed for bots without giving them a bounce they can learn from.

The product is still a directory: find a place, claim a place, pay for reach when you want it. Shipping the revenue path and deleting the metrics theater in the same week is the operator move.

If you own a shop between Asheville and Boone, what would you fix first on your BestWNC page: photos, hours, or the claim so nobody else can edit it?
