From 7200e21a524b197647a4e2acf05e942a1a744127 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 13 Oct 2026 19:06:55 -0700 Subject: [PATCH 1/6] improvement(seo): fix soft 404s, per-integration freshness, and docs markdown for AI crawlers --- apps/docs/app/[[...slug]]/page.tsx | 27 +- apps/docs/app/layout.tsx | 1 + apps/docs/components/footer/footer.tsx | 2 +- apps/docs/components/structured-data.tsx | 49 +- apps/docs/lib/llms.ts | 54 +- apps/docs/lib/redirects.ts | 66 ++ apps/docs/next.config.ts | 4 + apps/docs/package.json | 2 +- apps/docs/proxy.ts | 13 +- apps/docs/scripts/fetch-git-history.ts | 34 + apps/docs/scripts/generate-llms-full.ts | 4 +- apps/sim/app/(landing)/CLAUDE.md | 2 +- .../(landing)/blog/{ => (index)}/loading.tsx | 0 .../app/(landing)/blog/{ => (index)}/page.tsx | 0 .../sim/app/(landing)/blog/[slug]/loading.tsx | 5 - apps/sim/app/(landing)/blog/[slug]/page.tsx | 5 +- .../(landing)/blog/authors/[id]/loading.tsx | 5 - .../app/(landing)/blog/authors/[id]/page.tsx | 5 +- apps/sim/app/(landing)/changelog/page.tsx | 1 + .../(landing)/comparisons/[provider]/page.tsx | 1 + .../(landing)/components/footer/footer.tsx | 19 +- .../home-structured-data.tsx | 45 +- .../solutions-structured-data.tsx | 2 + .../integrations/(shell)/[slug]/loading.tsx | 9 - .../integrations/(shell)/[slug]/page.tsx | 25 +- .../library/{ => (index)}/loading.tsx | 0 .../(landing)/library/{ => (index)}/page.tsx | 0 .../app/(landing)/library/[slug]/loading.tsx | 5 - .../sim/app/(landing)/library/[slug]/page.tsx | 5 +- .../library/authors/[id]/loading.tsx | 5 - .../(landing)/library/authors/[id]/page.tsx | 5 +- .../(shell)/[provider]/[model]/loading.tsx | 9 - .../(shell)/[provider]/[model]/page.tsx | 23 +- .../models/(shell)/[provider]/loading.tsx | 9 - .../models/(shell)/[provider]/page.tsx | 5 +- .../pricing-structured-data.tsx | 5 +- apps/sim/app/sitemap.ts | 15 +- apps/sim/lib/blog/seo.ts | 1 + apps/sim/lib/content/seo.ts | 11 +- apps/sim/lib/integrations/types.ts | 2 + apps/sim/lib/landing/seo.ts | 4 + apps/sim/lib/library/seo.ts | 1 + apps/sim/proxy.ts | 18 +- .../deployment-config/src/integrations.json | 816 ++++++++++++------ scripts/generate-docs.ts | 32 +- 45 files changed, 885 insertions(+), 466 deletions(-) create mode 100644 apps/docs/scripts/fetch-git-history.ts rename apps/sim/app/(landing)/blog/{ => (index)}/loading.tsx (100%) rename apps/sim/app/(landing)/blog/{ => (index)}/page.tsx (100%) delete mode 100644 apps/sim/app/(landing)/blog/[slug]/loading.tsx delete mode 100644 apps/sim/app/(landing)/blog/authors/[id]/loading.tsx delete mode 100644 apps/sim/app/(landing)/integrations/(shell)/[slug]/loading.tsx rename apps/sim/app/(landing)/library/{ => (index)}/loading.tsx (100%) rename apps/sim/app/(landing)/library/{ => (index)}/page.tsx (100%) delete mode 100644 apps/sim/app/(landing)/library/[slug]/loading.tsx delete mode 100644 apps/sim/app/(landing)/library/authors/[id]/loading.tsx delete mode 100644 apps/sim/app/(landing)/models/(shell)/[provider]/[model]/loading.tsx delete mode 100644 apps/sim/app/(landing)/models/(shell)/[provider]/loading.tsx diff --git a/apps/docs/app/[[...slug]]/page.tsx b/apps/docs/app/[[...slug]]/page.tsx index faf8e255569..368dbf84614 100644 --- a/apps/docs/app/[[...slug]]/page.tsx +++ b/apps/docs/app/[[...slug]]/page.tsx @@ -1,5 +1,6 @@ import type React from 'react' import { Children, cloneElement, isValidElement } from 'react' +import { INTEGRATION_METADATA } from '@sim/deployment-config/integration-metadata' import { highlight } from 'fumadocs-core/highlight' import { findNeighbour } from 'fumadocs-core/page-tree' import type { ApiPageProps } from 'fumadocs-openapi/ui' @@ -20,10 +21,21 @@ import { ResponseSection } from '@/components/ui/response-section' import { getApiSpecContent, getAuthenticatedCodeSamples, openapi } from '@/lib/openapi' import { simShikiOptions } from '@/lib/shiki-theme' import { type PageData, source } from '@/lib/source' -import { DOCS_BASE_URL } from '@/lib/urls' +import { DOCS_BASE_URL, SIM_SITE_URL } from '@/lib/urls' const BASE_URL = DOCS_BASE_URL +/** + * Landing page for each docs integration page. Docs pages are keyed by block type without its + * version suffix (`gmail_v2` → `/integrations/gmail`); landing slugs are hyphenated catalog slugs. + */ +const INTEGRATION_LANDING_PAGES = new Map( + INTEGRATION_METADATA.map((integration) => [ + integration.type.replace(/_v\d+$/, ''), + { name: integration.name, url: `${SIM_SITE_URL}/integrations/${integration.slug}` }, + ]) +) + /** * Most pages close with a `## Next` / `## Next steps` grid of onward links. * That heading is navigation, not content, so it is kept out of the table of @@ -122,6 +134,10 @@ export default async function Page(props: { params: Promise<{ slug?: string[] }> } const isOpenAPI = '_openapi' in data && data._openapi != null const isApiReference = slug?.some((s) => s === 'api-reference') ?? false + const integrationLandingPage = + slug?.length === 2 && slug[0] === 'integrations' + ? INTEGRATION_LANDING_PAGES.get(slug[1]) + : undefined const isCli = slug?.[0] === 'cli' const isMcp = slug?.[0] === 'mcp' @@ -266,6 +282,14 @@ export default async function Page(props: { params: Promise<{ slug?: string[] }> + {integrationLandingPage && ( +

+ Use cases and templates:{' '} + + {integrationLandingPage.name} integration for AI agents + +

+ )}