fix(seo): noindex auth and docs crawl#2954
Conversation
Block auth/app pages from indexing, fix docs canonicals with robots/sitemap, drop model shipping schema and uptime sitemap bloat, and tighten page titles/meta.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThis PR updates docs and UI metadata routing, crawl directives, blog category pages, and model structured data, while standardizing shared URL/slug helpers across docs and UI. ChangesDocs and UI SEO updates
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/ui/src/app/reliability/page.tsx (1)
11-23: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd
Without a
title: "LLM Gateway - Unified API for Multiple LLM Providers"), which is wrong for the reliability page. Comparable pages (enterprise, pricing, legal, migration, providers/[id]) all include page-specific twitter metadata.🐦 Suggested addition
openGraph: { title: "Reliability & 99.9999% Uptime", description: "Automatic failover across providers, real-time health monitoring, and intelligent routing. Never go down, even when your providers do.", url: "https://llmgateway.io/reliability", type: "website", }, + twitter: { + card: "summary_large_image", + title: "Reliability & 99.9999% Uptime", + description: + "Automatic failover across providers, real-time health monitoring, and intelligent routing. Never go down, even when your providers do.", + }, };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/reliability/page.tsx` around lines 11 - 23, Add a page-specific twitter metadata block to the Reliability page’s Metadata export so it does not inherit the root layout’s generic social card. Update the `metadata` object in `page.tsx` alongside the existing `title`, `description`, and `openGraph` fields, matching the pattern used by the enterprise, pricing, legal, migration, and providers/[id] pages. Include the appropriate `twitter` values so social sharing for this route uses Reliability-specific text and card settings.apps/ui/src/app/ship/page.tsx (1)
8-20: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd
Without a
"LLM Gateway - Unified API for Multiple LLM Providers"), which is wrong for the ship page. Comparable pages (enterprise, pricing, legal, migration, providers/[id]) all include page-specific twitter metadata.🐦 Suggested addition
openGraph: { title: "Ship an AI App in 10 Minutes", description: "Clone a production-ready AI template, connect to 200+ models, and deploy. Ship your AI app in minutes with LLM Gateway.", url: "https://llmgateway.io/ship", type: "website", }, + twitter: { + card: "summary_large_image", + title: "Ship an AI App in 10 Minutes", + description: + "Clone a production-ready AI template, connect to 200+ models, and deploy. Ship your AI app in minutes with LLM Gateway.", + }, };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/ship/page.tsx` around lines 8 - 20, The page metadata in ship/page.tsx is missing a twitter block, so it inherits the root layout’s generic social card values. Update the exported metadata object in the ship page to include page-specific twitter metadata, matching the pattern used in the enterprise, pricing, legal, migration, and providers/[id] pages, so the ship page shares the correct title and description.
🧹 Nitpick comments (3)
apps/ui/src/app/blog/category/page.tsx (1)
8-13: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract
slugifyinto a shared utility.The
slugifyfunction is duplicated verbatim inapps/ui/src/app/blog/category/[category]/page.tsx(lines 15-20) and is also referenced inapps/ui/src/app/sitemap.ts. Extracting it to a shared utility (e.g.,@/lib/slugify) eliminates the copy-paste and ensures consistent slug generation across all three call sites.♻️ Proposed refactor
Create a shared utility, e.g.
apps/ui/src/lib/slugify.ts:export function slugify(label: string) { return label .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .replace(/(^-|-$)/g, ""); }Then replace both inline definitions with an import:
-import Link from "next/link"; +import Link from "next/link"; +import { slugify } from "`@/lib/slugify`";-function slugify(label: string) { - return label - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/(^-|-$)/g, ""); -}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/blog/category/page.tsx` around lines 8 - 13, The slugify logic is duplicated across the blog category page, the category detail page, and sitemap generation; extract the shared `slugify(label: string)` helper into a single utility like `@/lib/slugify` and update the existing inline usages in `page.tsx` and `sitemap.ts` to import it instead of redefining it. Keep the implementation centralized so all call sites use the same slug generation behavior.apps/ui/src/app/legal/[slug]/page.tsx (1)
83-89: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider using
openGraph.type: "article"for legal pages.Migration guide pages use
"article"foropenGraph.type, but legal pages use"website". Individual content pages (legal documents, guides) are more semantically"article"than"website". This is a minor SEO signal inconsistency.♻️ Suggested change
openGraph: { title: entry.title, description: entry.description ?? "LLM Gateway legal post", - type: "website", + type: "article", url: `https://llmgateway.io/legal/${entry.slug}`, },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/legal/`[slug]/page.tsx around lines 83 - 89, The Open Graph metadata in the legal page’s metadata generation currently uses openGraph.type as "website", which is inconsistent with other individual content pages. Update the metadata in the legal page component to use openGraph.type: "article" in the same object that sets title, description, and url, so the legal page aligns semantically with the guide pages.apps/ui/src/app/enterprise/page.tsx (1)
23-23: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor: title uses en dash (
–) instead of em dash (—).Most other page titles in this PR use an em dash (
—), e.g.,"LLM Gateway vs Portkey — The Open Portkey Alternative". The enterprise title uses an en dash (–):"Enterprise LLM Gateway – SSO, Audit Logs & Guardrails". Consider standardizing for visual consistency across the site.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/enterprise/page.tsx` at line 23, The Enterprise page title string in the metadata uses an en dash instead of the same em dash style used elsewhere. Update the title in the enterprise page component so it matches the site’s other page titles, keeping the wording the same but replacing the dash character for consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/docs/app/`(home)/[[...slug]]/page.tsx:
- Around line 33-35: Normalize DOCS_URL before building canonical and related
URLs so trailing slashes do not produce double-slash paths. Update the URL
construction in page.tsx around docsBaseUrl/canonicalUrl to use the same
normalization approach as layout.tsx (via new URL(...) or equivalent) before
concatenation, and apply the same fix in robots.ts and sitemap.ts where the docs
base URL is reused. Keep the path joining consistent so canonical, Open Graph,
robots, and sitemap URLs all resolve cleanly.
In `@apps/docs/app/robots.ts`:
- Around line 3-15: Add dynamic rendering to the docs metadata routes that
depend on DOCS_URL so they resolve the runtime host instead of being statically
emitted with the fallback value. Update robots() in robots.ts, and the matching
sitemap route, to export const dynamic = "force-dynamic" alongside the existing
MetadataRoute logic, mirroring the pattern already used in
apps/docs/app/layout.tsx.
---
Outside diff comments:
In `@apps/ui/src/app/reliability/page.tsx`:
- Around line 11-23: Add a page-specific twitter metadata block to the
Reliability page’s Metadata export so it does not inherit the root layout’s
generic social card. Update the `metadata` object in `page.tsx` alongside the
existing `title`, `description`, and `openGraph` fields, matching the pattern
used by the enterprise, pricing, legal, migration, and providers/[id] pages.
Include the appropriate `twitter` values so social sharing for this route uses
Reliability-specific text and card settings.
In `@apps/ui/src/app/ship/page.tsx`:
- Around line 8-20: The page metadata in ship/page.tsx is missing a twitter
block, so it inherits the root layout’s generic social card values. Update the
exported metadata object in the ship page to include page-specific twitter
metadata, matching the pattern used in the enterprise, pricing, legal,
migration, and providers/[id] pages, so the ship page shares the correct title
and description.
---
Nitpick comments:
In `@apps/ui/src/app/blog/category/page.tsx`:
- Around line 8-13: The slugify logic is duplicated across the blog category
page, the category detail page, and sitemap generation; extract the shared
`slugify(label: string)` helper into a single utility like `@/lib/slugify` and
update the existing inline usages in `page.tsx` and `sitemap.ts` to import it
instead of redefining it. Keep the implementation centralized so all call sites
use the same slug generation behavior.
In `@apps/ui/src/app/enterprise/page.tsx`:
- Line 23: The Enterprise page title string in the metadata uses an en dash
instead of the same em dash style used elsewhere. Update the title in the
enterprise page component so it matches the site’s other page titles, keeping
the wording the same but replacing the dash character for consistency.
In `@apps/ui/src/app/legal/`[slug]/page.tsx:
- Around line 83-89: The Open Graph metadata in the legal page’s metadata
generation currently uses openGraph.type as "website", which is inconsistent
with other individual content pages. Update the metadata in the legal page
component to use openGraph.type: "article" in the same object that sets title,
description, and url, so the legal page aligns semantically with the guide
pages.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fd4be167-15d7-404e-841d-2ddf08a86a98
📒 Files selected for processing (46)
apps/docs/app/(home)/[[...slug]]/page.tsxapps/docs/app/layout.tsxapps/docs/app/robots.tsapps/docs/app/sitemap.tsapps/ui/src/app/agents/page.tsxapps/ui/src/app/apps/page.tsxapps/ui/src/app/blog/category/[category]/page.tsxapps/ui/src/app/blog/category/page.tsxapps/ui/src/app/blog/page.tsxapps/ui/src/app/brand/layout.tsxapps/ui/src/app/brand/page.tsxapps/ui/src/app/changelog/[slug]/page.tsxapps/ui/src/app/compare/aws-bedrock/page.tsxapps/ui/src/app/compare/azure-ai-foundry/page.tsxapps/ui/src/app/compare/litellm/page.tsxapps/ui/src/app/compare/open-router/page.tsxapps/ui/src/app/compare/portkey/page.tsxapps/ui/src/app/compare/vercel-ai-gateway/page.tsxapps/ui/src/app/enterprise/page.tsxapps/ui/src/app/features/[slug]/page.tsxapps/ui/src/app/forgot-password/layout.tsxapps/ui/src/app/guides/[slug]/page.tsxapps/ui/src/app/layout.tsxapps/ui/src/app/legal/[slug]/page.tsxapps/ui/src/app/login/layout.tsxapps/ui/src/app/migration/[slug]/page.tsxapps/ui/src/app/models/[name]/[provider]/page.tsxapps/ui/src/app/models/[name]/page.tsxapps/ui/src/app/models/page.tsxapps/ui/src/app/nano-banana-simulator/[discount]/page.tsxapps/ui/src/app/onboarding/layout.tsxapps/ui/src/app/open-source/page.tsxapps/ui/src/app/pricing/page.tsxapps/ui/src/app/providers/[id]/page.tsxapps/ui/src/app/providers/page.tsxapps/ui/src/app/ref/[orgId]/page.tsxapps/ui/src/app/reliability/page.tsxapps/ui/src/app/reset-password/layout.tsxapps/ui/src/app/robots.tsapps/ui/src/app/ship/page.tsxapps/ui/src/app/signup/layout.tsxapps/ui/src/app/sitemap.tsapps/ui/src/app/sso/layout.tsxapps/ui/src/app/token-cost-calculator/page.tsxapps/ui/src/app/use-cases/page.tsxapps/ui/src/lib/rating-schema.ts
💤 Files with no reviewable changes (1)
- apps/ui/src/lib/rating-schema.ts
| export default function robots(): MetadataRoute.Robots { | ||
| const docsBaseUrl = process.env.DOCS_URL ?? "https://docs.llmgateway.io"; | ||
|
|
||
| return { | ||
| rules: [ | ||
| { | ||
| userAgent: "*", | ||
| allow: "/", | ||
| disallow: ["/api/", "/llms.mdx/", "/docs-og/"], | ||
| }, | ||
| ], | ||
| sitemap: `${docsBaseUrl}/sitemap.xml`, | ||
| }; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if other files in the docs app use force-dynamic alongside env var reads
rg -n "force-dynamic|dynamic.*=.*force" apps/docs/ --type=ts -C2Repository: theopenco/llmgateway
Length of output: 418
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the docs app files that read DOCS_URL and the robots route itself.
sed -n '1,120p' apps/docs/app/layout.tsx
printf '\n---\n'
sed -n '1,120p' apps/docs/app/robots.ts
printf '\n---\n'
rg -n "DOCS_URL|dynamic = \"force-dynamic\"" apps/docs/app -C 2Repository: theopenco/llmgateway
Length of output: 3605
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the robots route and nearby app route conventions.
sed -n '1,120p' apps/docs/app/robots.ts
printf '\n---\n'
sed -n '1,80p' apps/docs/app/layout.tsx
printf '\n---\n'
rg -n "export const dynamic|MetadataRoute.Robots|DOCS_URL" apps/docs/app -C 2Repository: theopenco/llmgateway
Length of output: 3674
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,120p' apps/docs/app/sitemap.tsRepository: theopenco/llmgateway
Length of output: 685
Add export const dynamic = "force-dynamic" to the docs metadata routes that read DOCS_URL. apps/docs/app/layout.tsx already does this, but apps/docs/app/robots.ts and apps/docs/app/sitemap.ts can otherwise be emitted with the fallback host instead of the runtime value.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/docs/app/robots.ts` around lines 3 - 15, Add dynamic rendering to the
docs metadata routes that depend on DOCS_URL so they resolve the runtime host
instead of being statically emitted with the fallback value. Update robots() in
robots.ts, and the matching sitemap route, to export const dynamic =
"force-dynamic" alongside the existing MetadataRoute logic, mirroring the
pattern already used in apps/docs/app/layout.tsx.
Address code-review findings on this PR: - ui robots.txt: stop disallowing noindexed auth/app pages so crawlers can see the noindex and actually deindex them; a bare /ref rule also prefix-blocked the public /referrals page and referral share previews - docs robots.txt: unblock /docs-og/ (og:image source) and /llms.mdx mirrors; serve X-Robots-Tag: noindex from the llms.mdx route instead - docs sitemap: drop build-time lastModified (unreliable signal) - docs: shared trailing-slash-safe docsBaseUrl in lib/base-url.ts - blog category pages: top-level content-collections imports, shared slugify in @/lib/slugify, label-based titles/descriptions, slugified canonicals, restored og:image, 404 unknown categories, drop latent single-category 307 redirect - nano-banana: canonicalize all discount variants to /20
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/ui/src/app/nano-banana-simulator/[discount]/page.tsx (1)
34-42: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
og:urlshould match the canonical URL for non-20 variants.All discount variants canonicalize to
/nano-banana-simulator/20, butog:urlremains parameterized (/nano-banana-simulator/${discount}). For any variant other than 20, this creates a mismatch: the canonical says "authoritative version is /20" whileog:urlsays "this page is /{discount}". Social platforms useog:urlfor engagement aggregation, so fragmented URLs dilute shares across variants instead of consolidating to /20. The blog category page in this same PR correctly alignsog:urlwith canonical — this page should follow suit.🔧 Proposed fix: align og:url with canonical
openGraph: { title: "Nano Banana Pro Cost Simulator", description: `See how much you save on Gemini 3 Pro image generation. ${discount}% savings vs Google AI Studio pricing.`, - url: `https://llmgateway.io/nano-banana-simulator/${discount}`, + url: "https://llmgateway.io/nano-banana-simulator/20", type: "website", },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/nano-banana-simulator/`[discount]/page.tsx around lines 34 - 42, The Nano Banana simulator metadata is inconsistent because the openGraph URL in the page component still points to the current discount while the canonical always points to /nano-banana-simulator/20. Update the metadata in the [discount]/page.tsx route so the openGraph.url matches the canonical value for all variants, using the existing page metadata object that defines alternates and openGraph.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@apps/ui/src/app/nano-banana-simulator/`[discount]/page.tsx:
- Around line 34-42: The Nano Banana simulator metadata is inconsistent because
the openGraph URL in the page component still points to the current discount
while the canonical always points to /nano-banana-simulator/20. Update the
metadata in the [discount]/page.tsx route so the openGraph.url matches the
canonical value for all variants, using the existing page metadata object that
defines alternates and openGraph.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 6c7c5197-7322-4c32-89a9-1a2278d8cb76
📒 Files selected for processing (13)
apps/docs/app/(home)/[[...slug]]/page.tsxapps/docs/app/layout.tsxapps/docs/app/llms.mdx/[[...slug]]/route.tsapps/docs/app/robots.tsapps/docs/app/sitemap.tsapps/docs/lib/base-url.tsapps/ui/src/app/blog/category/[category]/page.tsxapps/ui/src/app/blog/category/page.tsxapps/ui/src/app/nano-banana-simulator/[discount]/page.tsxapps/ui/src/app/robots.tsapps/ui/src/app/sitemap.tsapps/ui/src/components/blog/list.tsxapps/ui/src/lib/slugify.ts
✅ Files skipped from review due to trivial changes (1)
- apps/docs/lib/base-url.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/docs/app/(home)/[[...slug]]/page.tsx
The root layout's title.template re-appends "| LLM Gateway" to every <title> (so deduping page titles was correct), but Next.js does not apply the template to openGraph/twitter titles — dropping the brand there removed it from social cards entirely. Restore an explicit brand suffix on og/twitter titles across the affected pages, and add the missing og:image on /brand and /reliability.
|
Audit of the brand-removal in titles (follow-up commit
Verified against the built app: |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/ui/src/app/legal/[slug]/page.tsx (1)
83-92: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueConsider using
type: "article"for legal pages.Legal pages are standalone content documents. Using
type: "article"instead oftype: "website"would be more semantically appropriate for Open Graph and is consistent with how changelog entries are handled in the same PR.♻️ Suggested change
openGraph: { title: `${entry.title} | LLM Gateway`, description: entry.description ?? "LLM Gateway legal post", - type: "website", + type: "article", url: `https://llmgateway.io/legal/${entry.slug}`, },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/legal/`[slug]/page.tsx around lines 83 - 92, Update the metadata in the legal page’s page component so the Open Graph object for the slug-based legal entry uses type "article" instead of "website". Make this change in the metadata generation logic that sets alternates and openGraph, keeping the existing title, description, and url behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/ui/src/app/legal/`[slug]/page.tsx:
- Around line 83-92: Update the metadata in the legal page’s page component so
the Open Graph object for the slug-based legal entry uses type "article" instead
of "website". Make this change in the metadata generation logic that sets
alternates and openGraph, keeping the existing title, description, and url
behavior unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 14d08a7e-6749-4052-a115-f249438d0ee1
📒 Files selected for processing (15)
apps/ui/src/app/blog/category/[category]/page.tsxapps/ui/src/app/blog/category/page.tsxapps/ui/src/app/brand/layout.tsxapps/ui/src/app/brand/page.tsxapps/ui/src/app/changelog/[slug]/page.tsxapps/ui/src/app/guides/[slug]/page.tsxapps/ui/src/app/legal/[slug]/page.tsxapps/ui/src/app/migration/[slug]/page.tsxapps/ui/src/app/nano-banana-simulator/[discount]/page.tsxapps/ui/src/app/providers/[id]/page.tsxapps/ui/src/app/providers/page.tsxapps/ui/src/app/reliability/page.tsxapps/ui/src/app/ship/page.tsxapps/ui/src/app/token-cost-calculator/page.tsxapps/ui/src/app/use-cases/page.tsx
✅ Files skipped from review due to trivial changes (3)
- apps/ui/src/app/reliability/page.tsx
- apps/ui/src/app/providers/page.tsx
- apps/ui/src/app/use-cases/page.tsx
🚧 Files skipped from review as they are similar to previous changes (8)
- apps/ui/src/app/token-cost-calculator/page.tsx
- apps/ui/src/app/blog/category/page.tsx
- apps/ui/src/app/nano-banana-simulator/[discount]/page.tsx
- apps/ui/src/app/migration/[slug]/page.tsx
- apps/ui/src/app/brand/layout.tsx
- apps/ui/src/app/guides/[slug]/page.tsx
- apps/ui/src/app/brand/page.tsx
- apps/ui/src/app/blog/category/[category]/page.tsx
A single Offer makes the page a merchant-listing candidate, which requires shippingDetails/hasMerchantReturnPolicy — fields that do not apply to a digital API product and were removed earlier in this PR. AggregateOffer keeps the page eligible for product snippets (price + rating stars) without merchant-listing field requirements.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/ui/src/app/models/[name]/[provider]/page.tsx (1)
223-244: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low valueAggregateOffer structure looks correct.
The switch from
OffertoAggregateOfferwithofferCount: 1and matchinglowPrice/highPriceis well-formed. SinceAggregateOfferextendsOfferin schema.org, the inheritedpriceSpecification,availability,seller, andurlproperties are all valid here. The expliciturlpointing to the provider-specific page is correct — it differs from the canonical (which consolidates to the model page) but that's the right separation: structured data URL reflects the actual page, canonical manages crawl authority.One optional note: the pricing page precedent (
apps/ui/src/app/pricing/page.tsx) includes a nestedoffersarray with individualOfferobjects inside itsAggregateOffer. This page omits that nested array. Google will likely still parse the snippet correctly givenofferCountandlowPrice/highPrice, but adding a nestedOfferwith the sameurlandpricewould make the structured data more complete and consistent with the rest of the codebase.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/ui/src/app/models/`[name]/[provider]/page.tsx around lines 223 - 244, The AggregateOffer shape in the model page metadata is valid, but it is missing the nested individual Offer entry used elsewhere in the app for consistency. Update the structured data in the page component that builds the schema.org object so the AggregateOffer includes an offers array with a matching Offer object (same URL, price, currency, availability, and seller) similar to the pricing page implementation, while keeping the existing AggregateOffer fields unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/ui/src/app/models/`[name]/[provider]/page.tsx:
- Around line 223-244: The AggregateOffer shape in the model page metadata is
valid, but it is missing the nested individual Offer entry used elsewhere in the
app for consistency. Update the structured data in the page component that
builds the schema.org object so the AggregateOffer includes an offers array with
a matching Offer object (same URL, price, currency, availability, and seller)
similar to the pricing page implementation, while keeping the existing
AggregateOffer fields unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 7ae3901c-49ff-4424-ac0c-5cbcbf76e0a3
📒 Files selected for processing (1)
apps/ui/src/app/models/[name]/[provider]/page.tsx
Metadata routes don't inherit the root layout's force-dynamic, so both were prerendered at build time with the build-time DOCS_URL (usually the fallback) baked in. Forcing dynamic rendering resolves the runtime host, matching the pattern used in apps/docs/app/layout.tsx.
Summary
robots: noindex,nofollow. These paths are intentionally not disallowed in robots.txt — crawlers must be able to fetch a page to see the noindex, otherwise already-indexed URLs stay stuck as "Indexed, though blocked by robots.txt". Only/dashboardand/apiremain disallowed (a bare/refrule would also have prefix-blocked the public/referralspage and referral share previews).metadataBase+ self-canonicals point atdocs.llmgateway.io(was marketing homepage) via a shared trailing-slash-safelib/base-url.ts; addrobots.ts+sitemap.ts(no build-timelastModified) and title template%s | LLM Gateway Docs./docs-og/stays crawlable (it serves every docs og:image);/llms.mdxmarkdown mirrors serveX-Robots-Tag: noindexinstead of a robots.txt block so AI crawlers can still fetch them.sameAsGitHub URL totheopenco/llmgateway./models/*/uptimeURLs (still linked internally).og:url/canonicals on key hubs, real/blog/categoryindex with H1. Category pages resolve human-readable labels, use slugified canonicals, keep the site og:image, and 404 unknown categories; nano-banana discount variants canonicalize to/nano-banana-simulator/20.Left
force-dynamicin place (env vars loaded at runtime).Test plan
turbo run build --filter=ui --filter=docspasses/loginand/signupshownoindex, nofollowand are NOT blocked by robots.txtdocs.llmgateway.io/robots.txtand/sitemap.xml200 with self-canonicals on docs pages/llms.mdx/*responses carryX-Robots-Tag: noindexshippingDetails/MerchantReturnPolicySummary by CodeRabbit