From df2d1286d6c709236c2f8467ff443b79c402ec38 Mon Sep 17 00:00:00 2001 From: SnapOtter Date: Sat, 16 May 2026 23:11:39 +0800 Subject: [PATCH] fix(seo): add structured data for sitelinks and fix OG image Replace Organization schema with WebSite schema, add SiteNavigationElement for Documentation/FAQ/GitHub/Contact/Discord. Add BreadcrumbList to FAQ and Contact pages. Remove outdated og-image.svg (source already uses PNG). Update sitemap with lastmod and changefreq. --- apps/landing/public/og-image.svg | 12 ----- apps/landing/public/sitemap.xml | 12 ++++- apps/landing/src/app/contact/page.tsx | 11 +++++ apps/landing/src/app/faq/page.tsx | 10 ++++ apps/landing/src/app/page.tsx | 69 +++++++++++++++++++++++++-- 5 files changed, 96 insertions(+), 18 deletions(-) delete mode 100644 apps/landing/public/og-image.svg diff --git a/apps/landing/public/og-image.svg b/apps/landing/public/og-image.svg deleted file mode 100644 index 60a577a0..00000000 --- a/apps/landing/public/og-image.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - SnapOtter - Self-Hosted Image Processing - 50+ Tools · Local AI · 100% Offline · Open Source - diff --git a/apps/landing/public/sitemap.xml b/apps/landing/public/sitemap.xml index a0057647..b82bccd5 100644 --- a/apps/landing/public/sitemap.xml +++ b/apps/landing/public/sitemap.xml @@ -2,22 +2,32 @@ https://snapotter.com/ + 2026-05-16 + weekly 1.0 https://snapotter.com/faq - 0.7 + 2026-05-16 + monthly + 0.8 https://snapotter.com/contact + 2026-05-16 + monthly 0.7 https://snapotter.com/privacy + 2026-05-16 + yearly 0.3 https://snapotter.com/terms + 2026-05-16 + yearly 0.3 diff --git a/apps/landing/src/app/contact/page.tsx b/apps/landing/src/app/contact/page.tsx index c8b99620..bcc956bb 100644 --- a/apps/landing/src/app/contact/page.tsx +++ b/apps/landing/src/app/contact/page.tsx @@ -6,8 +6,18 @@ import { useState } from "react"; import { FadeIn } from "@/components/fade-in"; import { Footer } from "@/components/footer"; +import { JsonLd } from "@/components/json-ld"; import { Navbar } from "@/components/navbar"; +const breadcrumbJsonLd = { + "@context": "https://schema.org", + "@type": "BreadcrumbList", + itemListElement: [ + { "@type": "ListItem", position: 1, name: "Home", item: "https://snapotter.com" }, + { "@type": "ListItem", position: 2, name: "Contact", item: "https://snapotter.com/contact" }, + ], +}; + const benefits = [ { icon: Monitor, @@ -63,6 +73,7 @@ export default function ContactPage() { return ( <> +
diff --git a/apps/landing/src/app/faq/page.tsx b/apps/landing/src/app/faq/page.tsx index 5a13db7e..51b96702 100644 --- a/apps/landing/src/app/faq/page.tsx +++ b/apps/landing/src/app/faq/page.tsx @@ -85,10 +85,20 @@ const faqJsonLd = { })), }; +const breadcrumbJsonLd = { + "@context": "https://schema.org", + "@type": "BreadcrumbList", + itemListElement: [ + { "@type": "ListItem", position: 1, name: "Home", item: "https://snapotter.com" }, + { "@type": "ListItem", position: 2, name: "FAQ", item: "https://snapotter.com/faq" }, + ], +}; + export default function FaqPage() { return ( <> +
diff --git a/apps/landing/src/app/page.tsx b/apps/landing/src/app/page.tsx index 4680f0c5..ab21b273 100644 --- a/apps/landing/src/app/page.tsx +++ b/apps/landing/src/app/page.tsx @@ -15,13 +15,27 @@ export const metadata: Metadata = { alternates: { canonical: "https://snapotter.com" }, }; -const organizationJsonLd = { +const websiteJsonLd = { "@context": "https://schema.org", - "@type": "Organization", + "@type": "WebSite", name: "SnapOtter", url: "https://snapotter.com", - logo: "https://snapotter.com/logo.png", - sameAs: ["https://github.com/snapotter-hq/snapotter", "https://discord.gg/hr3s7HPUsr"], + description: + "52 image processing tools with local AI. Runs 100% offline. No data leaves your network.", + publisher: { + "@type": "Organization", + name: "SnapOtter", + url: "https://snapotter.com", + logo: { + "@type": "ImageObject", + url: "https://snapotter.com/logo.png", + }, + sameAs: [ + "https://github.com/snapotter-hq/snapotter", + "https://discord.gg/hr3s7HPUsr", + "https://hub.docker.com/r/snapotter/snapotter", + ], + }, }; const softwareJsonLd = { @@ -41,15 +55,60 @@ const softwareJsonLd = { url: "https://snapotter.com", downloadUrl: "https://hub.docker.com/r/snapotter/snapotter", screenshot: "https://snapotter.com/og-image.png", + image: "https://snapotter.com/og-image.png", featureList: "Image Resize, Image Crop, Image Compression, Format Conversion, Watermarking, Background Removal, Image Upscaling, OCR, Face Detection, Photo Restoration, Batch Processing, REST API, Pipeline Automation", }; +const navigationJsonLd = { + "@context": "https://schema.org", + "@type": "ItemList", + name: "SnapOtter Site Navigation", + itemListElement: [ + { + "@type": "SiteNavigationElement", + position: 1, + name: "Documentation", + description: "Installation guides, API reference, and configuration docs", + url: "https://docs.snapotter.com", + }, + { + "@type": "SiteNavigationElement", + position: 2, + name: "FAQ", + description: "Frequently asked questions about SnapOtter", + url: "https://snapotter.com/faq", + }, + { + "@type": "SiteNavigationElement", + position: 3, + name: "GitHub", + description: "Source code, issues, and discussions", + url: "https://github.com/snapotter-hq/snapotter", + }, + { + "@type": "SiteNavigationElement", + position: 4, + name: "Contact", + description: "Book a demo or discuss enterprise licensing", + url: "https://snapotter.com/contact", + }, + { + "@type": "SiteNavigationElement", + position: 5, + name: "Discord", + description: "Community chat and support", + url: "https://discord.gg/hr3s7HPUsr", + }, + ], +}; + export default function Home() { return ( <> - + +