Add OG/Twitter sharing metadata and screenshot for all marketing pages
- Update root layout with full Open Graph, Twitter Card, and SEO metadata
- Add OG image screenshot (1200x630) of the landing page hero
- Create layout.tsx with page-specific metadata for each marketing page
(welcome, features index, 8 feature detail pages, pricing)
- Use Next.js title template ("%s | Echo") for consistent page titles
- Add NEXT_PUBLIC_SITE_URL to .env.example for metadataBase config
Made-with: Cursor
This commit is contained in:
parent
7c4ec7bb9d
commit
c9f5b1e2ee
15 changed files with 244 additions and 2 deletions
|
|
@ -34,5 +34,8 @@ EMAIL_FROM_ADDRESS="mars@noreply.stillwell.cloud"
|
|||
# Vercel auto-sets this on Pro. Used to authenticate cron job requests.
|
||||
CRON_SECRET=""
|
||||
|
||||
# ─── Public site URL (used for OG metadata, canonical links) ─
|
||||
NEXT_PUBLIC_SITE_URL="https://echoocr.com"
|
||||
|
||||
# ─── Environment indicator ────────────────────────────────────
|
||||
NEXT_PUBLIC_ENV=""
|
||||
|
|
|
|||
BIN
public/og-image.png
Normal file
BIN
public/og-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 438 KiB |
17
src/app/(marketing)/features/ai-ocr/layout.tsx
Normal file
17
src/app/(marketing)/features/ai-ocr/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "AI-Powered OCR",
|
||||
description:
|
||||
"Echo's vision AI reads handwriting, checkboxes, and printed text — extracting 20+ fields per card including names, contact info, prayer requests, and spiritual decisions with over 95% accuracy.",
|
||||
openGraph: {
|
||||
title: "AI-Powered OCR | Echo",
|
||||
description:
|
||||
"Vision AI that reads handwriting, checkboxes, and printed text — 20+ fields per card with 95%+ accuracy.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function AiOcrLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/analytics/layout.tsx
Normal file
17
src/app/(marketing)/features/analytics/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Dashboard & Analytics",
|
||||
description:
|
||||
"See first-time guests, salvations, prayer requests, and follow-up status at a glance. Filter, sort, and export your data — powerful card tables with actionable guest insights.",
|
||||
openGraph: {
|
||||
title: "Dashboard & Analytics | Echo",
|
||||
description:
|
||||
"Real-time stats, powerful filtering, status tracking, and CSV export for your guest services data.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function AnalyticsLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/collection-days/layout.tsx
Normal file
17
src/app/(marketing)/features/collection-days/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Collection Days & Events",
|
||||
description:
|
||||
"Define recurring Sunday services and special events with flexible RFC 5545 scheduling. Echo auto-assigns scanned cards to the right event, keeping everything organized.",
|
||||
openGraph: {
|
||||
title: "Collection Days & Events | Echo",
|
||||
description:
|
||||
"Recurring services, special events, and automatic card-to-event assignment — keep everything organized.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function CollectionDaysLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/integrations/layout.tsx
Normal file
17
src/app/(marketing)/features/integrations/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Integrations",
|
||||
description:
|
||||
"Sync scanned card data to Planning Center, Google Sheets, Monday.com, Airtable, or any system via webhooks. Echo fits into the tools your church already uses.",
|
||||
openGraph: {
|
||||
title: "Integrations | Echo",
|
||||
description:
|
||||
"Planning Center, Google Sheets, Monday.com, Airtable, webhooks, and CSV export — Echo fits into your existing workflow.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function IntegrationsLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/layout.tsx
Normal file
17
src/app/(marketing)/features/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Features",
|
||||
description:
|
||||
"Explore Echo's full feature set — AI-powered OCR, scanner integration, team collaboration, multi-site management, analytics, and integrations with Planning Center, Google Sheets, and more.",
|
||||
openGraph: {
|
||||
title: "Features | Echo",
|
||||
description:
|
||||
"Everything your guest services team needs — from AI scanning to Planning Center sync.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function FeaturesLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/multi-site/layout.tsx
Normal file
17
src/app/(marketing)/features/multi-site/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Multi-Site Management",
|
||||
description:
|
||||
"Manage multiple campuses under one organization. Each location gets its own collection days, scanner setup, and team assignments — with unified reporting across all sites.",
|
||||
openGraph: {
|
||||
title: "Multi-Site Management | Echo",
|
||||
description:
|
||||
"Independent schedules per campus, unified processing pipeline, and organization-wide reporting.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function MultiSiteLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/scanner-integration/layout.tsx
Normal file
17
src/app/(marketing)/features/scanner-integration/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Scanner Integration",
|
||||
description:
|
||||
"Connect your office scanner via email or FTP and Echo picks up batches automatically. Or upload photos and PDFs from your phone — supports duplex scanning with front/back pairing.",
|
||||
openGraph: {
|
||||
title: "Scanner Integration | Echo",
|
||||
description:
|
||||
"Email, FTP, or drag-and-drop — get scanned cards into Echo however works best for your team.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function ScannerIntegrationLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/security/layout.tsx
Normal file
17
src/app/(marketing)/features/security/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Security & Privacy",
|
||||
description:
|
||||
"Role-based permissions, encrypted storage, email verification, invitation-only access, SSO support, and enterprise-grade infrastructure protect your congregation's personal data.",
|
||||
openGraph: {
|
||||
title: "Security & Privacy | Echo",
|
||||
description:
|
||||
"Encryption, RBAC, SSO, audit trails, and invitation-only access — your congregation's data stays safe.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function SecurityLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
17
src/app/(marketing)/features/team-collaboration/layout.tsx
Normal file
17
src/app/(marketing)/features/team-collaboration/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Team Collaboration",
|
||||
description:
|
||||
"Invite your pastoral care team with five role tiers, assign cards for follow-up, track review status, and keep everyone on the same page with in-app notifications.",
|
||||
openGraph: {
|
||||
title: "Team Collaboration | Echo",
|
||||
description:
|
||||
"Role-based access, card assignment, review workflows, and notifications for your whole team.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function TeamCollaborationLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
|
@ -1,3 +1,11 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
alternates: {
|
||||
canonical: "/welcome",
|
||||
},
|
||||
};
|
||||
|
||||
export default function MarketingLayout({
|
||||
children,
|
||||
}: {
|
||||
|
|
|
|||
17
src/app/(marketing)/pricing/layout.tsx
Normal file
17
src/app/(marketing)/pricing/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Pricing",
|
||||
description:
|
||||
"Simple, transparent pricing for churches of every size. Start free with 50 cards/month, then scale as you grow. All paid plans include a 14-day free trial.",
|
||||
openGraph: {
|
||||
title: "Pricing | Echo",
|
||||
description:
|
||||
"Start free with 50 cards/month. Upgrade when you're ready — no contract, no commitment.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
};
|
||||
|
||||
export default function PricingLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
16
src/app/(marketing)/welcome/layout.tsx
Normal file
16
src/app/(marketing)/welcome/layout.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Echo — AI-Powered Response Card Scanning for Churches",
|
||||
description:
|
||||
"Stop hand-typing visitor cards. Echo uses AI to scan guest cards, prayer requests, and response forms — then syncs to Planning Center, your CRM, or wherever your team needs it.",
|
||||
openGraph: {
|
||||
title: "Echo — AI-Powered Response Card Scanning for Churches",
|
||||
description:
|
||||
"Stop hand-typing visitor cards. Scan guest cards with AI and sync to Planning Center in seconds.",
|
||||
},
|
||||
};
|
||||
|
||||
export default function WelcomeLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
|
@ -9,9 +9,54 @@ const quicksand = Quicksand({
|
|||
weight: ["300", "400", "500", "600", "700"],
|
||||
});
|
||||
|
||||
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || "https://echoocr.com";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Echo OCR",
|
||||
description: "Response card scanning and management",
|
||||
title: {
|
||||
default: "Echo — AI-Powered Response Card Scanning for Churches",
|
||||
template: "%s | Echo",
|
||||
},
|
||||
description:
|
||||
"Stop hand-typing visitor cards. Echo uses AI to scan guest cards, prayer requests, and response forms — then syncs to Planning Center, your CRM, or wherever your team needs it.",
|
||||
metadataBase: new URL(siteUrl),
|
||||
openGraph: {
|
||||
type: "website",
|
||||
siteName: "Echo",
|
||||
title: "Echo — AI-Powered Response Card Scanning for Churches",
|
||||
description:
|
||||
"Stop hand-typing visitor cards. Echo uses AI to scan guest cards, prayer requests, and response forms — then syncs to Planning Center, your CRM, or wherever your team needs it.",
|
||||
images: [
|
||||
{
|
||||
url: "/og-image.png",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "Echo — Stop hand-typing visitor cards",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Echo — AI-Powered Response Card Scanning for Churches",
|
||||
description:
|
||||
"Stop hand-typing visitor cards. Echo uses AI to scan guest cards, prayer requests, and response forms — then syncs to Planning Center, your CRM, or wherever your team needs it.",
|
||||
images: ["/og-image.png"],
|
||||
},
|
||||
keywords: [
|
||||
"church OCR",
|
||||
"visitor card scanning",
|
||||
"guest card scanner",
|
||||
"response card digitization",
|
||||
"Planning Center integration",
|
||||
"church management",
|
||||
"AI OCR",
|
||||
"prayer request scanning",
|
||||
"connection card scanner",
|
||||
"church guest services",
|
||||
],
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
|
|
|||
Loading…
Reference in a new issue