Boring Docs
SEO, Analytics, Blog — Ship + Measure + Write
Metadata helpers, self-hosted beacon, markdown posts.
In this guide
SEO, Analytics, Blog
SEO
libs/seo.js:getSEOTags({ title, description, keywords, openGraph, canonicalUrlRelative, extraTags }) — mounted in app/layout.js, overridable per page. Structured data via renderSiteSchemas() (Organization/WebSite/FAQ/Breadcrumb) and per-article JSON-LD. Sitemap: next-sitemap.config.js (SITE_URL, excludes images/icons). Keep ratings/prices truthful — fake aggregate values risk rich-result penalties.
Analytics (self-hosted, separate DB)
- Write:
track(event, properties, { userId, url })fromproviders/analytics/index.js. Cookie sessionbsk_sid, 30-min idle, anon→authed promotion, 64KB property cap, never throws. - Read:
providers/analytics/stats.js(overview,topPages/Events/Countries,rangeMetrics,dailySeries, funnels). Dashboard at/dashboard/analytics. - Beacon:
POST /api/analytics/track(unauthenticated by design; anonymous counts). Validate lengths server-side; add in-app rate limits if abused. - Storage:
analytics.sqlitenext to app DB (WAL). Prune:npm run analytics:cleanup(scripts/analytics-cleanup.mjs, default 90 days, cron daily). Include it in volume snapshots.
Blog
libs/blog.js reads data/blog/<slug>.md (frontmatter title, description, date, tags), renders via gray-matter + marked once per mtime (in-memory cache). Routes: /blog, /blog/[articleId], author/category pages. Body rendered with dangerouslySetInnerHTML — safe only because files are repo-owned; sanitize before rendering if authorship ever opens up.