Production ready
This commit is contained in:
170
frontend/app/features/[slug]/page.tsx
Normal file
170
frontend/app/features/[slug]/page.tsx
Normal file
@@ -0,0 +1,170 @@
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeft } from 'lucide-react'
|
||||
import { Footer } from '@/components/layout/Footer'
|
||||
import { notFound } from 'next/navigation'
|
||||
|
||||
const features: Record<string, {
|
||||
title: string
|
||||
metaDescription: string
|
||||
intro: string
|
||||
howItWorks: string
|
||||
vsAlternatives: string
|
||||
faqs: { q: string; a: string }[]
|
||||
}> = {
|
||||
'noise-filtering': {
|
||||
title: 'AI Noise Filtering',
|
||||
metaDescription: 'SiteChangeMonitor uses AI to automatically filter out cookie banners, timestamps, rotating ads, and session IDs — delivering zero-noise website change alerts.',
|
||||
intro: 'AI Noise Filtering is the core feature that sets SiteChangeMonitor apart. It automatically identifies and filters out irrelevant page changes — cookie banners, footer timestamps, rotating ads, and session-specific content — so you only receive alerts for meaningful updates.',
|
||||
howItWorks: 'Our AI analyzes each page change in context. It recognizes common noise patterns (date stamps, consent popups, A/B test variations, ad rotations) and suppresses them automatically. You can also add custom ignore rules using CSS selectors, regex patterns, or plain text matching.',
|
||||
vsAlternatives: 'Visualping and Distill.io require manual configuration of ignore rules, which most users skip — leading to constant false alerts. SiteChangeMonitor applies smart noise filtering by default, significantly reducing false positives without any setup.',
|
||||
faqs: [
|
||||
{ q: 'Does AI filtering work on all websites?', a: 'Yes. Our filtering engine recognizes common noise patterns across all site types — SPAs, e-commerce, news sites, and more. You can also add custom rules for edge cases.' },
|
||||
{ q: 'Can I customize what gets filtered?', a: 'Absolutely. You can add custom ignore rules (CSS selectors, regex, text patterns) on top of the automatic AI filtering.' },
|
||||
{ q: 'Will I miss important changes?', a: 'No. The AI only filters known noise patterns. Any change it cannot confidently classify as noise is passed through to you.' },
|
||||
],
|
||||
},
|
||||
'visual-diff': {
|
||||
title: 'Visual Diff & Screenshots',
|
||||
metaDescription: 'See exactly what changed on any web page with side-by-side screenshot diffs. SiteChangeMonitor provides visual proof of every change.',
|
||||
intro: 'Visual Diff gives you screenshot-based proof of every website change. Instead of parsing raw HTML diffs, see side-by-side visual comparisons that highlight exactly what changed on the page.',
|
||||
howItWorks: 'SiteChangeMonitor captures full-page screenshots on every check. When a change is detected, we generate a visual diff that highlights modified areas. You can compare any two snapshots in your version history.',
|
||||
vsAlternatives: 'Distill.io offers text-based diffs only. UptimeRobot has no diff capability. Visualping offers visual diffs but lacks AI noise filtering, so most of the changes shown are irrelevant noise.',
|
||||
faqs: [
|
||||
{ q: 'What format are the screenshots?', a: 'Screenshots are captured as full-page PNG images and stored with timestamps for audit purposes.' },
|
||||
{ q: 'Can I compare any two versions?', a: 'Yes. You can select any two snapshots from the version history and generate a visual diff between them.' },
|
||||
{ q: 'Are screenshots included in the free plan?', a: 'Yes, visual diffs are available on all plans including the Forever Free tier.' },
|
||||
],
|
||||
},
|
||||
'keyword-monitoring': {
|
||||
title: 'Keyword Monitoring',
|
||||
metaDescription: 'Set keyword triggers on any web page. Get alerted when specific words appear, disappear, or cross a count threshold. SiteChangeMonitor keyword monitoring.',
|
||||
intro: 'Keyword Monitoring lets you set precise triggers for when specific words or phrases appear, disappear, or cross a count threshold on any monitored page. Ideal for tracking pricing terms, product availability, job postings, and competitive messaging.',
|
||||
howItWorks: 'Add one or more keyword rules to any monitor. Choose trigger type: "appears" (word added to page), "disappears" (word removed), or "count" (word frequency crosses a threshold). Supports exact match and regex patterns.',
|
||||
vsAlternatives: 'UptimeRobot offers basic keyword checking but no appear/disappear logic. Distill.io supports conditions but requires complex selector configuration. SiteChangeMonitor makes keyword monitoring a first-class feature with a simple UI.',
|
||||
faqs: [
|
||||
{ q: 'Can I use regex for keyword matching?', a: 'Yes. You can use full regular expressions for complex pattern matching, such as price formats ($XX.XX) or phone numbers.' },
|
||||
{ q: 'What is a count threshold trigger?', a: 'Count triggers alert you when a keyword appears more (or fewer) than N times on a page. Useful for tracking inventory counts or job listing volumes.' },
|
||||
{ q: 'Can I combine keyword alerts with noise filtering?', a: 'Yes. Noise filtering runs first, then keyword checks run on the cleaned content — ensuring accurate keyword detection.' },
|
||||
],
|
||||
},
|
||||
'seo-ranking': {
|
||||
title: 'SEO & Ranking Alerts',
|
||||
metaDescription: 'Monitor search engine ranking changes, featured snippet movements, and SERP updates. SiteChangeMonitor alerts SEO teams to ranking shifts.',
|
||||
intro: 'SEO & Ranking Alerts help SEO professionals track changes in search engine results pages. Monitor your target keywords for ranking shifts, featured snippet ownership changes, and new competitor appearances.',
|
||||
howItWorks: 'Point a monitor at a Google search results URL for your keyword. SiteChangeMonitor captures the SERP from a clean, non-personalized browser session and alerts you when rankings change. AI filtering removes localized variations.',
|
||||
vsAlternatives: 'Dedicated SEO tools like Ahrefs and SEMrush track rankings but cost $99+/month and are built for large-scale keyword tracking. SiteChangeMonitor is ideal for focused SERP monitoring at a fraction of the cost.',
|
||||
faqs: [
|
||||
{ q: 'Does this replace my SEO rank tracker?', a: 'It complements rank trackers by providing instant alerts on SERP changes. Use it for your most important keywords that need real-time monitoring.' },
|
||||
{ q: 'How do you handle personalized results?', a: 'We use clean, non-personalized browser sessions from consistent locations to ensure results are not skewed by personal search history.' },
|
||||
{ q: 'Can I track featured snippets?', a: 'Yes. Set a keyword trigger for your brand name in the featured snippet area to know instantly when you gain or lose the snippet.' },
|
||||
],
|
||||
},
|
||||
'multi-channel-alerts': {
|
||||
title: 'Multi-Channel Alerts',
|
||||
metaDescription: 'Get website change notifications via email, Slack, or webhooks. SiteChangeMonitor delivers alerts where your team works.',
|
||||
intro: 'Multi-Channel Alerts deliver website change notifications where your team already works — email, Slack, or webhooks. Route different monitors to different channels based on urgency and team.',
|
||||
howItWorks: 'Configure alert channels per monitor or globally. Each channel can have its own rules: immediate alerts for critical monitors, daily digests for informational ones. Webhooks support custom payloads for integration with any system.',
|
||||
vsAlternatives: 'Visualping restricts Slack integration to enterprise plans. Distill.io supports basic notifications but lacks channel routing. SiteChangeMonitor includes Slack and webhook channels on Pro plans and above, with email alerts on every plan.',
|
||||
faqs: [
|
||||
{ q: 'Is Slack included in the free plan?', a: 'Slack and webhook integrations are available on Pro and Business plans. The free plan includes email notifications.' },
|
||||
{ q: 'Can I set up digest emails?', a: 'Yes. Choose between instant alerts and daily or weekly digest emails that summarize all changes across your monitors.' },
|
||||
{ q: 'Do webhooks support custom payloads?', a: 'Yes. You can customize the webhook payload format to integrate with any system — Zapier, Make, n8n, or your own API.' },
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return Object.keys(features).map((slug) => ({ slug }))
|
||||
}
|
||||
|
||||
export function generateMetadata({ params }: { params: { slug: string } }): Metadata {
|
||||
const data = features[params.slug]
|
||||
if (!data) return {}
|
||||
return {
|
||||
title: data.title,
|
||||
description: data.metaDescription,
|
||||
alternates: { canonical: `/features/${params.slug}` },
|
||||
openGraph: { title: data.title, description: data.metaDescription, url: `/features/${params.slug}` },
|
||||
}
|
||||
}
|
||||
|
||||
export default function FeaturePage({ params }: { params: { slug: string } }) {
|
||||
const data = features[params.slug]
|
||||
if (!data) notFound()
|
||||
|
||||
const faqJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
mainEntity: data.faqs.map((faq) => ({
|
||||
'@type': 'Question',
|
||||
name: faq.q,
|
||||
acceptedAnswer: { '@type': 'Answer', text: faq.a },
|
||||
})),
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqJsonLd) }}
|
||||
/>
|
||||
<div className="flex-1 py-24 px-6">
|
||||
<div className="mx-auto max-w-4xl space-y-12">
|
||||
<div className="space-y-4">
|
||||
<Link href="/features" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground transition-colors">
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
All Features
|
||||
</Link>
|
||||
<h1 className="text-4xl md:text-5xl font-bold font-display text-foreground">
|
||||
{data.title}
|
||||
</h1>
|
||||
<p className="text-xl text-muted-foreground max-w-3xl">{data.intro}</p>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<h2 className="text-2xl font-bold text-foreground mb-4">How It Works</h2>
|
||||
<p className="text-muted-foreground">{data.howItWorks}</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="text-2xl font-bold text-foreground mb-4">vs. Alternatives</h2>
|
||||
<p className="text-muted-foreground">{data.vsAlternatives}</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2 className="text-2xl font-bold text-foreground mb-6">FAQ</h2>
|
||||
<dl className="space-y-6">
|
||||
{data.faqs.map((faq, i) => (
|
||||
<div key={i}>
|
||||
<dt className="font-medium text-foreground">{faq.q}</dt>
|
||||
<dd className="mt-1 text-muted-foreground">{faq.a}</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
{/* CTA */}
|
||||
<section className="text-center py-12">
|
||||
<h2 className="text-2xl font-bold text-foreground mb-4">Try {data.title}</h2>
|
||||
<p className="text-muted-foreground mb-6">Join the waitlist for early access.</p>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center rounded-full bg-primary px-8 py-3 font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
|
||||
>
|
||||
Join the Waitlist
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
{/* Internal Links */}
|
||||
<nav className="flex flex-wrap gap-3 text-sm">
|
||||
<Link href="/features" className="text-primary hover:underline">All Features</Link>
|
||||
<span className="text-muted-foreground">•</span>
|
||||
<Link href="/use-cases" className="text-primary hover:underline">Use Cases</Link>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
112
frontend/app/features/page.tsx
Normal file
112
frontend/app/features/page.tsx
Normal file
@@ -0,0 +1,112 @@
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeft } from 'lucide-react'
|
||||
import { Footer } from '@/components/layout/Footer'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Features — AI-Powered Website Change Detection',
|
||||
description:
|
||||
'Explore SiteChangeMonitor features: AI noise filtering, visual diffs, keyword monitoring, SEO ranking alerts, and multi-channel notifications.',
|
||||
alternates: { canonical: '/features' },
|
||||
openGraph: {
|
||||
title: 'Features — SiteChangeMonitor',
|
||||
description: 'AI noise filtering, visual diffs, keyword alerts, and more.',
|
||||
url: '/features',
|
||||
},
|
||||
}
|
||||
|
||||
const features = [
|
||||
{
|
||||
slug: 'noise-filtering',
|
||||
title: 'AI Noise Filtering',
|
||||
description: 'Automatically ignore cookie banners, timestamps, ads, and session IDs. Only get alerted on meaningful changes.',
|
||||
},
|
||||
{
|
||||
slug: 'visual-diff',
|
||||
title: 'Visual Diff & Screenshots',
|
||||
description: 'See exactly what changed with side-by-side screenshot comparisons. Audit-proof visual evidence for every change.',
|
||||
},
|
||||
{
|
||||
slug: 'keyword-monitoring',
|
||||
title: 'Keyword Monitoring',
|
||||
description: 'Set triggers for when specific words appear or disappear on a page. Track pricing terms, product names, or any keyword.',
|
||||
},
|
||||
{
|
||||
slug: 'seo-ranking',
|
||||
title: 'SEO & Ranking Alerts',
|
||||
description: 'Monitor SERP changes, featured snippets, and competitor ranking movements for your target keywords.',
|
||||
},
|
||||
{
|
||||
slug: 'multi-channel-alerts',
|
||||
title: 'Multi-Channel Alerts',
|
||||
description: 'Get notified via email, Slack, webhooks, or Teams. Route different monitors to different channels.',
|
||||
},
|
||||
]
|
||||
|
||||
const itemListJsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'ItemList',
|
||||
itemListElement: features.map((f, i) => ({
|
||||
'@type': 'ListItem',
|
||||
position: i + 1,
|
||||
name: f.title,
|
||||
url: `https://sitechangemonitor.com/features/${f.slug}`,
|
||||
})),
|
||||
}
|
||||
|
||||
export default function FeaturesPage() {
|
||||
return (
|
||||
<div className="min-h-screen bg-background flex flex-col">
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(itemListJsonLd) }}
|
||||
/>
|
||||
<div className="flex-1 py-24 px-6">
|
||||
<div className="mx-auto max-w-5xl space-y-12">
|
||||
<div className="space-y-4">
|
||||
<Link href="/" className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground transition-colors">
|
||||
<ArrowLeft className="mr-2 h-4 w-4" />
|
||||
Back to Home
|
||||
</Link>
|
||||
<h1 className="text-4xl md:text-5xl font-bold font-display text-foreground">
|
||||
Features
|
||||
</h1>
|
||||
<p className="text-xl text-muted-foreground max-w-3xl">
|
||||
SiteChangeMonitor combines AI-powered noise filtering with visual diffs, keyword alerts, and multi-channel notifications to deliver zero-noise website change detection.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{features.map((f) => (
|
||||
<Link
|
||||
key={f.slug}
|
||||
href={`/features/${f.slug}`}
|
||||
className="group rounded-2xl border border-border bg-card p-8 hover:border-primary/50 transition-colors"
|
||||
>
|
||||
<h2 className="text-xl font-bold text-foreground group-hover:text-primary transition-colors">
|
||||
{f.title}
|
||||
</h2>
|
||||
<p className="mt-2 text-muted-foreground">{f.description}</p>
|
||||
<span className="mt-4 inline-block text-sm font-medium text-primary">
|
||||
Learn more →
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<section className="text-center py-12">
|
||||
<h2 className="text-2xl font-bold text-foreground mb-4">Ready to try it?</h2>
|
||||
<p className="text-muted-foreground mb-6">Join the waitlist for early access to every feature.</p>
|
||||
<Link
|
||||
href="/"
|
||||
className="inline-flex items-center rounded-full bg-primary px-8 py-3 font-medium text-primary-foreground hover:bg-primary/90 transition-colors"
|
||||
>
|
||||
Join the Waitlist
|
||||
</Link>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user