diff --git a/astro.config.mjs b/astro.config.mjs
index ba7857e03..99296d0be 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -318,10 +318,20 @@ export default defineConfig({
}),
icon(),
sitemap({
- filter: (page) => !page.includes('404'),
- customPages: [
- 'https://docs.kinde.com/'
- ]
+ filter: (page) => {
+ // Include all documentation pages
+ if (page.includes('/docs/')) return true;
+ // Include main pages
+ if (page === '' || page === '/') return true;
+ // Include API pages
+ if (page.includes('/kinde-apis/')) return true;
+ // Exclude admin or private pages
+ if (page.includes('/admin/')) return false;
+ return true;
+ },
+ changefreq: 'weekly',
+ priority: 0.7,
+ lastmod: new Date()
}),
AutoImport({
imports: [
diff --git a/public/robots.txt b/public/robots.txt
index c923e543f..5c1b0cb72 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -1,5 +1,21 @@
User-agent: *
Allow: /
-# Sitemap
-Sitemap: https://docs.kinde.com/sitemap-0.xml
\ No newline at end of file
+# Sitemap location
+Sitemap: https://docs.kinde.com/sitemap-0.xml
+
+# Crawl delay for respectful crawling
+Crawl-delay: 1
+
+# Allow all major search engines
+User-agent: Googlebot
+Allow: /
+
+User-agent: Bingbot
+Allow: /
+
+User-agent: Slurp
+Allow: /
+
+# Disallow admin or private areas (if any exist in the future)
+Disallow: /admin/
diff --git a/src/content.config.ts b/src/content.config.ts
index 464c94624..b30b27bcf 100644
--- a/src/content.config.ts
+++ b/src/content.config.ts
@@ -10,7 +10,20 @@ export const collections = {
page_id: z.string().uuid(),
relatedArticles: z.string().array().optional().nullable(),
app_context: z.array(z.any()).optional(),
- social_sharing_image_url: z.string().optional()
+ social_sharing_image_url: z.string().optional(),
+ // Enhanced metadata for SEO - made more flexible to match existing content
+ metadata: z.object({
+ topics: z.array(z.string()).optional(),
+ sdk: z.array(z.string()).optional(),
+ languages: z.array(z.string()).optional(),
+ audience: z.array(z.string()).optional(),
+ complexity: z.enum(['beginner', 'intermediate', 'advanced']).optional(),
+ keywords: z.array(z.string()).optional(),
+ updated: z.union([z.string(), z.date()]).optional(), // Allow both string and date
+ featured: z.boolean().optional(),
+ deprecated: z.boolean().optional(),
+ 'ai-summary': z.string().optional()
+ }).optional()
})
})
}),
diff --git a/src/pages/docs-suggestions.json.ts b/src/pages/docs-suggestions.json.ts
index 70344fdce..660e6d380 100644
--- a/src/pages/docs-suggestions.json.ts
+++ b/src/pages/docs-suggestions.json.ts
@@ -5,12 +5,38 @@ export const GET: APIRoute = () => {
return new Response(
JSON.stringify(
- Object.keys(docs).map((url) => ({
- page_id: docs[url].frontmatter.page_id,
- title: docs[url].frontmatter.title,
- url: "https://docs.kinde.com" + url.split("/content/docs")[1].split(".")[0] + "/",
- app_context: docs[url].frontmatter.app_context
- })),
+ Object.keys(docs).map((url) => {
+ const frontmatter = docs[url].frontmatter;
+ const metadata = frontmatter.metadata || {};
+
+ return {
+ page_id: frontmatter.page_id,
+ title: frontmatter.title,
+ description: frontmatter.description,
+ url: "https://docs.kinde.com" + url.split("/content/docs")[1].split(".")[0] + "/",
+ app_context: frontmatter.app_context,
+ // Enhanced metadata for search indexing
+ topics: metadata.topics || [],
+ keywords: metadata.keywords || [],
+ audience: metadata.audience || [],
+ complexity: metadata.complexity,
+ sdk: metadata.sdk || [],
+ languages: metadata.languages || [],
+ updated: metadata.updated,
+ featured: metadata.featured,
+ deprecated: metadata.deprecated,
+ ai_summary: metadata['ai-summary'],
+ // SEO-friendly content snippets
+ content_preview: frontmatter.description || metadata['ai-summary'] || '',
+ search_terms: [
+ ...(metadata.keywords || []),
+ ...(metadata.topics || []),
+ ...(metadata.audience || []),
+ frontmatter.title,
+ metadata.complexity
+ ].filter(Boolean).join(' ')
+ };
+ }),
null,
2
)
diff --git a/src/starlight-overrides/Head.astro b/src/starlight-overrides/Head.astro
index 119c3fd3f..59a16159c 100644
--- a/src/starlight-overrides/Head.astro
+++ b/src/starlight-overrides/Head.astro
@@ -2,19 +2,115 @@
import Default from "@astrojs/starlight/components/Head.astro";
import type {Props} from "@astrojs/starlight/props";
+const { entry } = Astro.props;
const hasCustomOGImage = Astro.props.entry.data.head.find((t) =>
t.attrs.property === "og:image" ? true : false
);
----
-{
- import.meta.env.PUBLIC_IS_ANALYTICS_ENABLED === "true" && (
-
- )
+// Extract metadata from frontmatter - handle both patterns
+// Pattern 1: metadata wrapper object
+// Pattern 2: fields directly in frontmatter
+const metadata = entry.data.metadata || {};
+const directFields = entry.data as any;
+
+// Combine both sources, with metadata wrapper taking precedence
+const keywords = metadata.keywords || directFields.keywords || [];
+const topics = metadata.topics || directFields.topics || [];
+const audience = metadata.audience || directFields.audience || [];
+const complexity = metadata.complexity || directFields.complexity;
+const updated = metadata.updated || directFields.updated;
+const featured = metadata.featured || directFields.featured;
+const deprecated = metadata.deprecated || directFields.deprecated;
+const aiSummary = metadata['ai-summary'] || directFields['ai-summary'];
+
+// Handle updated field - convert date to string if needed
+const updatedString = updated instanceof Date ? updated.toISOString() : updated;
+
+// Combine keywords from different sources
+const allKeywords = [
+ ...keywords,
+ ...topics,
+ ...audience,
+ complexity,
+ entry.data.title,
+ entry.data.description
+].filter(Boolean);
+
+// Create structured data for better SEO
+const structuredData: any = {
+ "@context": "https://schema.org",
+ "@type": "TechArticle",
+ "headline": entry.data.title,
+ "description": entry.data.description,
+ "keywords": allKeywords.join(", "),
+ "author": {
+ "@type": "Organization",
+ "name": "Kinde"
+ },
+ "publisher": {
+ "@type": "Organization",
+ "name": "Kinde",
+ "url": "https://kinde.com"
+ },
+ "mainEntityOfPage": {
+ "@type": "WebPage",
+ "@id": Astro.url.href
+ },
+ "articleSection": topics.join(", "),
+ "articleBody": entry.data.description,
+ "wordCount": entry.data.description?.length || 0,
+ "dateModified": updatedString,
+ "inLanguage": "en-US",
+ "isAccessibleForFree": true,
+ "educationalLevel": complexity || "Beginner",
+ "audience": {
+ "@type": "Audience",
+ "audienceType": audience.join(", ")
+ }
+};
+
+// Add featured/deprecated status if available
+if (featured !== undefined) {
+ structuredData.isPartOf = {
+ "@type": "CreativeWork",
+ "isFeatured": featured
+ };
+}
+
+if (deprecated !== undefined) {
+ structuredData.isDeprecated = deprecated;
}
+---
+
+
+
+
+
+
+
+
+{updatedString && }
+{featured && }
+{deprecated && }
+
+
+
+
+
+{complexity && }
+{updatedString && }
+
+
+
+{allKeywords.length > 0 && }
+
+
+
-
-
-
+
+{aiSummary && }
-{!hasCustomOGImage && }
+
+{!hasCustomOGImage && entry.data.social_sharing_image_url && (
+
+)}