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.
This commit is contained in:
SnapOtter
2026-05-16 23:11:39 +08:00
parent 148118d969
commit df2d1286d6
5 changed files with 96 additions and 18 deletions
-12
View File
@@ -1,12 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630" viewBox="0 0 1200 630">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#f59e0b"/>
<stop offset="100%" style="stop-color:#ea580c"/>
</linearGradient>
</defs>
<rect width="1200" height="630" fill="url(#bg)"/>
<text x="600" y="280" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="72" font-weight="800" fill="white">SnapOtter</text>
<text x="600" y="350" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="28" font-weight="400" fill="rgba(255,255,255,0.85)">Self-Hosted Image Processing</text>
<text x="600" y="400" text-anchor="middle" font-family="system-ui, -apple-system, sans-serif" font-size="20" font-weight="400" fill="rgba(255,255,255,0.6)">50+ Tools · Local AI · 100% Offline · Open Source</text>
</svg>

Before

Width:  |  Height:  |  Size: 935 B

+11 -1
View File
@@ -2,22 +2,32 @@
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url> <url>
<loc>https://snapotter.com/</loc> <loc>https://snapotter.com/</loc>
<lastmod>2026-05-16</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority> <priority>1.0</priority>
</url> </url>
<url> <url>
<loc>https://snapotter.com/faq</loc> <loc>https://snapotter.com/faq</loc>
<priority>0.7</priority> <lastmod>2026-05-16</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url> </url>
<url> <url>
<loc>https://snapotter.com/contact</loc> <loc>https://snapotter.com/contact</loc>
<lastmod>2026-05-16</lastmod>
<changefreq>monthly</changefreq>
<priority>0.7</priority> <priority>0.7</priority>
</url> </url>
<url> <url>
<loc>https://snapotter.com/privacy</loc> <loc>https://snapotter.com/privacy</loc>
<lastmod>2026-05-16</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority> <priority>0.3</priority>
</url> </url>
<url> <url>
<loc>https://snapotter.com/terms</loc> <loc>https://snapotter.com/terms</loc>
<lastmod>2026-05-16</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority> <priority>0.3</priority>
</url> </url>
</urlset> </urlset>
+11
View File
@@ -6,8 +6,18 @@ import { useState } from "react";
import { FadeIn } from "@/components/fade-in"; import { FadeIn } from "@/components/fade-in";
import { Footer } from "@/components/footer"; import { Footer } from "@/components/footer";
import { JsonLd } from "@/components/json-ld";
import { Navbar } from "@/components/navbar"; 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 = [ const benefits = [
{ {
icon: Monitor, icon: Monitor,
@@ -63,6 +73,7 @@ export default function ContactPage() {
return ( return (
<> <>
<JsonLd data={breadcrumbJsonLd} />
<Navbar /> <Navbar />
<main className="pt-16"> <main className="pt-16">
<section className="px-6 py-24 md:py-32"> <section className="px-6 py-24 md:py-32">
+10
View File
@@ -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() { export default function FaqPage() {
return ( return (
<> <>
<JsonLd data={faqJsonLd} /> <JsonLd data={faqJsonLd} />
<JsonLd data={breadcrumbJsonLd} />
<Navbar /> <Navbar />
<main className="pt-16"> <main className="pt-16">
<section className="px-6 py-24 md:py-32"> <section className="px-6 py-24 md:py-32">
+64 -5
View File
@@ -15,13 +15,27 @@ export const metadata: Metadata = {
alternates: { canonical: "https://snapotter.com" }, alternates: { canonical: "https://snapotter.com" },
}; };
const organizationJsonLd = { const websiteJsonLd = {
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "Organization", "@type": "WebSite",
name: "SnapOtter", name: "SnapOtter",
url: "https://snapotter.com", url: "https://snapotter.com",
logo: "https://snapotter.com/logo.png", description:
sameAs: ["https://github.com/snapotter-hq/snapotter", "https://discord.gg/hr3s7HPUsr"], "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 = { const softwareJsonLd = {
@@ -41,15 +55,60 @@ const softwareJsonLd = {
url: "https://snapotter.com", url: "https://snapotter.com",
downloadUrl: "https://hub.docker.com/r/snapotter/snapotter", downloadUrl: "https://hub.docker.com/r/snapotter/snapotter",
screenshot: "https://snapotter.com/og-image.png", screenshot: "https://snapotter.com/og-image.png",
image: "https://snapotter.com/og-image.png",
featureList: 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", "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() { export default function Home() {
return ( return (
<> <>
<JsonLd data={organizationJsonLd} /> <JsonLd data={websiteJsonLd} />
<JsonLd data={softwareJsonLd} /> <JsonLd data={softwareJsonLd} />
<JsonLd data={navigationJsonLd} />
<Navbar /> <Navbar />
<main> <main>
<Hero /> <Hero />