Ecosystem directory for NEAR Protocol
Table of Contents
npm installhere is sample env file:
NEAR_CATALOG_API=https://api.nearcatalog.xyz
NEXT_PUBLIC_NEAR_CATALOG_API=https://api.nearcatalog.xyz
BASE_URL=http://nearcatalog.xyz
# Optional. Set "false" to hide programmatic FAQ sections + FAQPage JSON-LD.
NEXT_PUBLIC_FAQ_ENABLED=true
# Optional. IndexNow integration. Generate via `openssl rand -hex 32`.
INDEXNOW_KEY=
CRON_SECRET=
Routes shipped:
/sitemap.xml— HTML +.mdcompanion URLs withlastmod(project = APIupdated_atw/ fallback to build time; category = max of children; static routes = git mtime)./robots.txt— wildcardAllow, plus explicit allow rules for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, Applebot-Extended, Amazonbot, Meta-ExternalAgent./llms.txt— header overview + featured projects + categories list, links to full + index./llms-full.txt— concatenated Markdown bodies of categories + featured + projects, capped at 500 KB with truncation note./llms-index.txt— newline-separated list of every.mdURL./ai.txt— explicit per-bot AI usage policy.- Markdown companions:
/project/<pid>.md,/category/<cid>.md—text/markdownwithLink: <canonical>; rel="canonical"header. Rewritten from/md/...backing routes. - JSON-LD per page: Organization (site-wide), WebSite + SearchAction, BreadcrumbList, Article (project), SoftwareApplication (project), Speakable, FAQPage (project + category, env-gated).
- FAQ section on project + category pages — visible
<details>blocks + matching FAQPage JSON-LD. Toggle off both withNEXT_PUBLIC_FAQ_ENABLED=false(cloaking-safe: section AND schema disappear together). - IndexNow daily ping via
/api/cron/indexnow(Vercel Cron, scheduled invercel.jsonat 04:00 UTC).
- Env vars in Vercel (Project → Settings → Environment Variables):
NEAR_CATALOG_API,NEXT_PUBLIC_NEAR_CATALOG_API,BASE_URL(existing)NEXT_PUBLIC_FAQ_ENABLED— setfalseto hide FAQ sections + schema; leave unset/trueto show them.INDEXNOW_KEY— generate:openssl rand -hex 32. The key file is auto-served at/<KEY>.txtvia app/[key]/route.ts.CRON_SECRET— generate:openssl rand -hex 32. Vercel Cron injectsAuthorization: Bearer <CRON_SECRET>automatically; the route at app/api/cron/indexnow/route.ts rejects requests without it.
- Bing / IndexNow registration:
- Sign in to Bing Webmaster Tools, add the site, verify ownership.
- Submit
https://nearcatalog.xyz/sitemap.xml. - Under IndexNow, register the same
INDEXNOW_KEY. Bing infers the key file location from the host.
- Smoke-test endpoints after deploy:
BASE=https://nearcatalog.xyz curl -sI $BASE/sitemap.xml | head -3 curl -sI $BASE/llms.txt | head -3 curl -sI $BASE/llms-full.txt | head -3 curl -sI $BASE/llms-index.txt | head -3 curl -sI $BASE/ai.txt | head -3 curl -sI $BASE/project/<some-pid>.md | grep -i 'content-type\|link' curl -sI $BASE/category/<some-cid>.md | grep -i 'content-type\|link' curl -sI $BASE/$INDEXNOW_KEY.txt # 200
- Trigger first IndexNow run manually:
Expected JSON:
curl -X GET https://nearcatalog.xyz/api/cron/indexnow \ -H "Authorization: Bearer $CRON_SECRET"{ ok: true, host, total, results: [{ batch, status, count }] }. Status200or202from IndexNow is success. - Verify schemas:
- Paste a project URL + a category URL into Google Rich Results Test — expect Article, BreadcrumbList, SoftwareApplication, FAQPage (or none if FAQ disabled), Speakable.
- Paste home into Schema.org validator — expect Organization, WebSite.
- Confirm bot access:
curl -A "GPTBot" https://nearcatalog.xyz/ | grep '<h1\|ld+json'— should return SSR HTML + JSON-LD.
- Adding a new programmatic route: also add it to app/sitemap.ts
staticRoutes, give it a<h1>(usesr-onlyif sharedSectionHeadingalready renders<h2>), wire<BreadcrumbSchema>, and addalternates.canonicalin itsgenerateMetadata. - Editing FAQ templates: lib/seo/faq.ts. After editing, run
pnpm seo:lint:faqto confirm pairwise Jaccard similarity stays under 0.85 across pages. - Editing Markdown companions: shape lives in lib/render/markdown.ts; content shape in lib/content/project.ts + lib/content/category.ts. After changes run
pnpm seo:lint:md-parityagainst a running server to confirm HTML ↔ .md Jaccard ≥ 0.90. - Disabling FAQ temporarily: set
NEXT_PUBLIC_FAQ_ENABLED=falsein Vercel → redeploy. Both visible section + JSON-LD disappear together. - Rotating IndexNow key: generate new
INDEXNOW_KEY, update Vercel env, redeploy, re-register in Bing Webmaster Tools (old key file 404s once env rotates). - Pausing IndexNow: disable the cron entry in vercel.json or remove
INDEXNOW_KEY(route returns 500). No code change needed. - Run all SEO lints locally before a release:
CI runs the same on every PR via .github/workflows/seo-lint.yml.
pnpm build && pnpm start & # start server in background SEO_LINT_BASE_URL=http://localhost:3000 pnpm seo:lint
| Concern | File |
|---|---|
| JSON-LD components | components/seo/json-ld.tsx |
| FAQ component | components/seo/faq-section.tsx |
| FAQ templates + env flag | lib/seo/faq.ts |
| Breadcrumb builders | lib/seo/breadcrumbs.ts |
| dateModified resolution | lib/seo/date-modified.ts |
| Markdown content shapes | lib/content/project.ts, lib/content/category.ts |
| Markdown rendering | lib/render/markdown.ts |
| Sitemap | app/sitemap.ts |
| robots | app/robots.ts |
| LLM endpoints | app/llms.txt/route.ts, app/llms-full.txt/route.ts, app/llms-index.txt/route.ts |
.md companions |
app/md/project/[pid]/route.ts, app/md/category/[cid]/route.ts |
| IndexNow key file | app/[key]/route.ts |
| IndexNow cron | app/api/cron/indexnow/route.ts, vercel.json |
| Static AI policy | public/ai.txt |
| SEO lints | scripts/seo/ |
First, run the development server:
npm run devOpen http://localhost:3000 in your browser to see the result.
npm run buildnpm run testSee the full testing guide.
This is a Next.js project bootstrapped with create-next-app.
It uses next/font to automatically optimize and load Manrope, a custom Google Font.
This project uses the Next.js App Router, and so the routes are defined in the app folder. There are three main pages:
/: Home page of the application. It displays a list of projects that are available on the NEAR platform./project/:projectId: Displays the details of a specific project. It includes information about the project, such as the name, description, and the list of tags associated with the project./category/:categoryId: Displays a list of projects that are associated with a specific category.
zustand is used to manage global state. It is a state management library that provides a simple and scalable solution for managing application state in a React or Preact application.
The state is stored in the store folder. There are two stores that are used in this project:
search-store.ts: Manages the search state, including the search query and the tags that are selected.tags-modal-store.ts: Manages the state of the tags modal for mobile devices.search-modal-store.ts: Manages the state of search modal.
You can see the public APIs of NEARCatalog Indexer here: https://docs.nearcatalog.xyz/
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you're interested in contributing to this project, please read the contribution guide.