feat: initialize landing page with dynamic competitor comparison routes and structured SEO metadata
This commit is contained in:
@@ -1208,14 +1208,291 @@ h3 {
|
||||
margin-bottom: var(--s2);
|
||||
}
|
||||
|
||||
.support-faq-item p {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* =============================================
|
||||
RESPONSIVE
|
||||
============================================= */
|
||||
@media (max-width: 1024px) {
|
||||
.support-faq-item p {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
/* =============================================
|
||||
COMPARISON PAGES
|
||||
============================================= */
|
||||
.comparison-page {
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(86, 160, 116, 0.16), transparent 26%),
|
||||
linear-gradient(180deg, var(--cream) 0%, var(--white) 100%);
|
||||
}
|
||||
|
||||
.comparison-hero {
|
||||
background:
|
||||
linear-gradient(135deg, rgba(13, 22, 15, 0.96) 0%, rgba(28, 46, 33, 0.92) 45%, rgba(42, 92, 63, 0.86) 100%);
|
||||
color: var(--cream);
|
||||
padding: 11rem 0 5rem;
|
||||
}
|
||||
|
||||
.comparison-hero-grid,
|
||||
.comparison-context-grid,
|
||||
.comparison-fit-grid,
|
||||
.comparison-links-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1.2fr 0.8fr;
|
||||
gap: var(--s4);
|
||||
}
|
||||
|
||||
.comparison-hero-copy h1 {
|
||||
max-width: 12ch;
|
||||
margin-bottom: var(--s3);
|
||||
}
|
||||
|
||||
.comparison-lead,
|
||||
.comparison-disclaimer,
|
||||
.comparison-context-card p,
|
||||
.comparison-thesis-copy p,
|
||||
.comparison-row-verdict,
|
||||
.comparison-faq-card p,
|
||||
.comparison-link-card p,
|
||||
.comparison-scenario-copy p {
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.comparison-lead {
|
||||
max-width: 700px;
|
||||
color: rgba(244, 241, 232, 0.86);
|
||||
font-size: 1.08rem;
|
||||
}
|
||||
|
||||
.comparison-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s2);
|
||||
margin: var(--s4) 0 var(--s3);
|
||||
}
|
||||
|
||||
.comparison-disclaimer,
|
||||
.comparison-verified {
|
||||
font-size: 0.82rem;
|
||||
color: rgba(244, 241, 232, 0.72);
|
||||
}
|
||||
|
||||
.comparison-hero-card,
|
||||
.comparison-context-card,
|
||||
.comparison-pain-card,
|
||||
.comparison-thesis-card,
|
||||
.comparison-fit-card,
|
||||
.comparison-scenario-card,
|
||||
.comparison-faq-card,
|
||||
.comparison-link-card,
|
||||
.comparison-row {
|
||||
border-radius: var(--r-lg);
|
||||
box-shadow: 0 24px 60px rgba(19, 31, 22, 0.08);
|
||||
}
|
||||
|
||||
.comparison-hero-card {
|
||||
background: rgba(244, 241, 232, 0.08);
|
||||
border: 1px solid rgba(244, 241, 232, 0.12);
|
||||
padding: var(--s4);
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.comparison-hero-card h2 {
|
||||
font-size: clamp(1.55rem, 2.2vw, 2.2rem);
|
||||
margin-bottom: var(--s3);
|
||||
}
|
||||
|
||||
.comparison-card-label,
|
||||
.comparison-mini-label {
|
||||
display: inline-block;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.comparison-card-label {
|
||||
color: var(--green-light);
|
||||
margin-bottom: var(--s2);
|
||||
}
|
||||
|
||||
.comparison-mini-label {
|
||||
color: var(--accent);
|
||||
margin-bottom: 0.55rem;
|
||||
}
|
||||
|
||||
.comparison-bullet-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
.comparison-bullet-list li {
|
||||
position: relative;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.comparison-bullet-list li::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0.7rem;
|
||||
left: 0;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 50%;
|
||||
background: var(--accent);
|
||||
}
|
||||
|
||||
.comparison-bullet-list--dark li::before {
|
||||
background: var(--green-mid);
|
||||
}
|
||||
|
||||
.comparison-context,
|
||||
.comparison-theses,
|
||||
.comparison-table-section,
|
||||
.comparison-fit,
|
||||
.comparison-emergency,
|
||||
.comparison-faq,
|
||||
.comparison-links {
|
||||
padding: var(--s12) 0;
|
||||
}
|
||||
|
||||
.comparison-context-card,
|
||||
.comparison-pain-card,
|
||||
.comparison-thesis-card,
|
||||
.comparison-fit-card,
|
||||
.comparison-scenario-card,
|
||||
.comparison-faq-card,
|
||||
.comparison-link-card {
|
||||
background: rgba(255, 255, 255, 0.86);
|
||||
border: 1px solid rgba(19, 31, 22, 0.08);
|
||||
padding: var(--s4);
|
||||
}
|
||||
|
||||
.comparison-context-card h2,
|
||||
.comparison-fit-card h2,
|
||||
.comparison-link-card h3 {
|
||||
margin-bottom: var(--s2);
|
||||
}
|
||||
|
||||
.comparison-context-card--accent,
|
||||
.comparison-fit-card--greenlens {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(86, 160, 116, 0.12) 0%, rgba(255, 255, 255, 0.96) 100%);
|
||||
}
|
||||
|
||||
.comparison-section-head {
|
||||
max-width: 720px;
|
||||
margin-bottom: var(--s4);
|
||||
}
|
||||
|
||||
.comparison-section-head h2 {
|
||||
color: var(--dark);
|
||||
}
|
||||
|
||||
.comparison-pain-grid,
|
||||
.comparison-scenario-grid,
|
||||
.comparison-faq-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: var(--s3);
|
||||
}
|
||||
|
||||
.comparison-pain-card {
|
||||
background: var(--dark);
|
||||
color: var(--cream);
|
||||
}
|
||||
|
||||
.comparison-pain-card h3,
|
||||
.comparison-thesis-card h3,
|
||||
.comparison-scenario-card h3,
|
||||
.comparison-faq-card h3 {
|
||||
margin-bottom: var(--s2);
|
||||
}
|
||||
|
||||
.comparison-thesis-copy,
|
||||
.comparison-scenario-copy {
|
||||
display: grid;
|
||||
gap: var(--s3);
|
||||
}
|
||||
|
||||
.comparison-table {
|
||||
display: grid;
|
||||
gap: var(--s3);
|
||||
}
|
||||
|
||||
.comparison-table-header {
|
||||
display: grid;
|
||||
grid-template-columns: 0.75fr 1fr 1fr;
|
||||
gap: var(--s3);
|
||||
padding: 0 var(--s2);
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.comparison-row {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: 1px solid rgba(19, 31, 22, 0.08);
|
||||
display: grid;
|
||||
grid-template-columns: 0.75fr 1fr 1fr;
|
||||
gap: var(--s3);
|
||||
padding: var(--s3);
|
||||
}
|
||||
|
||||
.comparison-row-title {
|
||||
font-family: var(--display);
|
||||
font-size: 1.4rem;
|
||||
color: var(--dark);
|
||||
}
|
||||
|
||||
.comparison-cell {
|
||||
padding: var(--s3);
|
||||
border-radius: var(--r-md);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.comparison-cell--greenlens {
|
||||
background: rgba(86, 160, 116, 0.12);
|
||||
border: 1px solid rgba(86, 160, 116, 0.18);
|
||||
}
|
||||
|
||||
.comparison-cell--competitor {
|
||||
background: rgba(19, 31, 22, 0.05);
|
||||
border: 1px solid rgba(19, 31, 22, 0.08);
|
||||
}
|
||||
|
||||
.comparison-row-verdict {
|
||||
grid-column: 1 / -1;
|
||||
margin-top: 0.2rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.comparison-links-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.comparison-link-card {
|
||||
display: block;
|
||||
transition: transform var(--t), box-shadow var(--t);
|
||||
}
|
||||
|
||||
.comparison-link-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 20px 50px rgba(19, 31, 22, 0.12);
|
||||
}
|
||||
|
||||
.comparison-link-card--support {
|
||||
background: var(--dark);
|
||||
color: var(--cream);
|
||||
}
|
||||
|
||||
.comparison-link-card--support .comparison-mini-label,
|
||||
.comparison-link-card--support p {
|
||||
color: rgba(244, 241, 232, 0.76);
|
||||
}
|
||||
|
||||
/* =============================================
|
||||
RESPONSIVE
|
||||
============================================= */
|
||||
@media (max-width: 1024px) {
|
||||
.hero .container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@@ -1266,13 +1543,29 @@ h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.footer-inner {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--s6);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.footer-inner {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--s6);
|
||||
}
|
||||
|
||||
.comparison-hero-grid,
|
||||
.comparison-context-grid,
|
||||
.comparison-fit-grid,
|
||||
.comparison-links-grid,
|
||||
.comparison-pain-grid,
|
||||
.comparison-scenario-grid,
|
||||
.comparison-faq-grid,
|
||||
.comparison-table-header,
|
||||
.comparison-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.comparison-row-title {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-links {
|
||||
display: none;
|
||||
}
|
||||
@@ -1315,8 +1608,34 @@ h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.support-grid,
|
||||
.support-faq-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.support-grid,
|
||||
.support-faq-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.comparison-hero {
|
||||
padding-top: 9rem;
|
||||
}
|
||||
|
||||
.comparison-actions {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.comparison-pain-grid,
|
||||
.comparison-scenario-grid,
|
||||
.comparison-faq-grid,
|
||||
.comparison-links-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.comparison-context,
|
||||
.comparison-theses,
|
||||
.comparison-table-section,
|
||||
.comparison-fit,
|
||||
.comparison-emergency,
|
||||
.comparison-faq,
|
||||
.comparison-links {
|
||||
padding: var(--s8) 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,20 +28,11 @@ export const metadata: Metadata = {
|
||||
description: 'Identify plants, get care guidance, and manage your collection with GreenLens.',
|
||||
type: 'website',
|
||||
url: siteConfig.domain,
|
||||
images: [
|
||||
{
|
||||
url: '/og-image.png',
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: 'GreenLens – Plant Identifier and Care Planner',
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: 'GreenLens - Plant Identifier and Care Planner',
|
||||
description: 'Identify plants, get care guidance, and manage your collection with GreenLens.',
|
||||
images: ['/og-image.png'],
|
||||
},
|
||||
alternates: {
|
||||
canonical: '/',
|
||||
|
||||
83
greenlns-landing/app/opengraph-image.tsx
Normal file
83
greenlns-landing/app/opengraph-image.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { ImageResponse } from 'next/og'
|
||||
|
||||
export const runtime = 'edge'
|
||||
export const alt = 'GreenLens – Plant Identifier and Care Planner'
|
||||
export const size = { width: 1200, height: 630 }
|
||||
export const contentType = 'image/png'
|
||||
|
||||
export default function OGImage() {
|
||||
return new ImageResponse(
|
||||
(
|
||||
<div
|
||||
style={{
|
||||
background: '#131f16',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: '80px',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 26,
|
||||
fontWeight: 600,
|
||||
color: '#56a074',
|
||||
letterSpacing: '0.15em',
|
||||
textTransform: 'uppercase',
|
||||
marginBottom: 28,
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
Plant Identifier & Care App
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: 100,
|
||||
fontWeight: 800,
|
||||
color: '#f4f1e8',
|
||||
marginBottom: 28,
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
GreenLens
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: 34,
|
||||
color: 'rgba(244,241,232,0.65)',
|
||||
textAlign: 'center',
|
||||
maxWidth: 820,
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
Identify plants, get AI-powered care plans, and manage your collection.
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 56, display: 'flex', gap: 16 }}>
|
||||
{['450+ plant species', 'AI-powered scans', 'iOS & Android'].map((label) => (
|
||||
<div
|
||||
key={label}
|
||||
style={{
|
||||
background: 'rgba(86,160,116,0.15)',
|
||||
border: '1.5px solid rgba(86,160,116,0.4)',
|
||||
borderRadius: 100,
|
||||
padding: '14px 30px',
|
||||
fontSize: 22,
|
||||
color: '#7ac99a',
|
||||
display: 'flex',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
{ ...size },
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,38 @@ import FAQ from '@/components/FAQ'
|
||||
import CTA from '@/components/CTA'
|
||||
import Footer from '@/components/Footer'
|
||||
|
||||
const howToSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'HowTo',
|
||||
name: 'How to identify a plant with GreenLens',
|
||||
step: [
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 1,
|
||||
name: 'Photograph your plant',
|
||||
text: 'Open the app, point the camera at your plant and tap Scan.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 2,
|
||||
name: 'AI identifies instantly',
|
||||
text: 'In under a second you get the exact name, species and all key details.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 3,
|
||||
name: 'Receive care plan',
|
||||
text: 'GreenLens automatically creates a personalized care plan for your plant and location.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 4,
|
||||
name: 'Track growth',
|
||||
text: 'Document photos, track watering and get reminded of important care dates.',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const faqSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
@@ -34,7 +66,7 @@ const faqSchema = {
|
||||
name: 'Can I use GreenLens offline?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: 'Some experiences may require a connection, especially for scan-related features. Saved information inside the app can remain available afterward.',
|
||||
text: 'Plant identification and health checks require an internet connection. Your saved collection, care notes, and watering reminders are available offline.',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -42,7 +74,7 @@ const faqSchema = {
|
||||
name: 'What kind of plants can I use GreenLens for?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: 'GreenLens is built for everyday plant owners who want help with houseplants, garden plants, and general care questions.',
|
||||
text: 'GreenLens covers 450+ plant species including houseplants, garden plants, and succulents. It is built for everyday plant owners who want identification and care guidance in one place.',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -59,6 +91,10 @@ const faqSchema = {
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(howToSchema) }}
|
||||
/>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
|
||||
|
||||
@@ -16,6 +16,18 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.5,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/vs/picturethis`,
|
||||
lastModified: new Date('2026-04-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.65,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/vs/plantum`,
|
||||
lastModified: new Date('2026-04-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.65,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/imprint`,
|
||||
lastModified: new Date('2026-04-08'),
|
||||
|
||||
70
greenlns-landing/app/vs/[competitor]/page.tsx
Normal file
70
greenlns-landing/app/vs/[competitor]/page.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import type { Metadata } from 'next'
|
||||
import { notFound } from 'next/navigation'
|
||||
import ComparisonPage from '@/components/ComparisonPage'
|
||||
import { competitorOrder, getCompetitorBySlug, getPeerCompetitors } from '@/lib/competitors'
|
||||
import { siteConfig } from '@/lib/site'
|
||||
|
||||
type ComparisonRouteProps = {
|
||||
params: Promise<{ competitor: string }>
|
||||
}
|
||||
|
||||
export function generateStaticParams() {
|
||||
return competitorOrder.map((competitor) => ({ competitor }))
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: ComparisonRouteProps): Promise<Metadata> {
|
||||
const { competitor } = await params
|
||||
const profile = getCompetitorBySlug(competitor)
|
||||
|
||||
if (!profile) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const path = `/vs/${profile.slug}`
|
||||
|
||||
return {
|
||||
title: profile.metaTitle,
|
||||
description: profile.metaDescription,
|
||||
alternates: {
|
||||
canonical: path,
|
||||
},
|
||||
keywords: [
|
||||
`${siteConfig.name.toLowerCase()} vs ${profile.name.toLowerCase()}`,
|
||||
`${profile.name.toLowerCase()} alternative`,
|
||||
'plant emergency app',
|
||||
'plant care app comparison',
|
||||
'plant diagnosis app',
|
||||
],
|
||||
openGraph: {
|
||||
title: profile.metaTitle,
|
||||
description: profile.metaDescription,
|
||||
url: `${siteConfig.domain}${path}`,
|
||||
type: 'website',
|
||||
images: [
|
||||
{
|
||||
url: '/og-image.png',
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: `${profile.metaTitle} comparison page`,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: profile.metaTitle,
|
||||
description: profile.metaDescription,
|
||||
images: ['/og-image.png'],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default async function ComparisonRoute({ params }: ComparisonRouteProps) {
|
||||
const { competitor } = await params
|
||||
const profile = getCompetitorBySlug(competitor)
|
||||
|
||||
if (!profile) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
return <ComparisonPage competitor={profile} peers={getPeerCompetitors(profile.slug)} />
|
||||
}
|
||||
236
greenlns-landing/components/ComparisonPage.tsx
Normal file
236
greenlns-landing/components/ComparisonPage.tsx
Normal file
@@ -0,0 +1,236 @@
|
||||
import Link from 'next/link'
|
||||
import Navbar from '@/components/Navbar'
|
||||
import CTA from '@/components/CTA'
|
||||
import Footer from '@/components/Footer'
|
||||
import type { CompetitorProfile } from '@/lib/competitors'
|
||||
import { siteConfig } from '@/lib/site'
|
||||
|
||||
interface ComparisonPageProps {
|
||||
competitor: CompetitorProfile
|
||||
peers: CompetitorProfile[]
|
||||
}
|
||||
|
||||
export default function ComparisonPage({ competitor, peers }: ComparisonPageProps) {
|
||||
const faqSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
mainEntity: competitor.faqs.map((item) => ({
|
||||
'@type': 'Question',
|
||||
name: item.question,
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: item.answer,
|
||||
},
|
||||
})),
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }}
|
||||
/>
|
||||
<Navbar />
|
||||
<main className="comparison-page">
|
||||
<section className="comparison-hero">
|
||||
<div className="container comparison-hero-grid">
|
||||
<div className="comparison-hero-copy">
|
||||
<p className="tag">Comparison</p>
|
||||
<h1>{siteConfig.name} vs {competitor.name}</h1>
|
||||
<p className="comparison-lead">{competitor.heroSummary}</p>
|
||||
<div className="comparison-actions">
|
||||
<a href="#cta" className="btn-primary">Try GreenLens</a>
|
||||
<a href="#comparison-table" className="btn-outline">See full comparison</a>
|
||||
</div>
|
||||
<p className="comparison-disclaimer">{competitor.disclaimer}</p>
|
||||
</div>
|
||||
|
||||
<aside className="comparison-hero-card">
|
||||
<p className="comparison-card-label">Fast verdict</p>
|
||||
<h2>Pick GreenLens when your plant already looks wrong.</h2>
|
||||
<ul className="comparison-bullet-list">
|
||||
{competitor.heroVerdict.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className="comparison-verified">Research summary refreshed {competitor.lastVerified}</p>
|
||||
</aside>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-context">
|
||||
<div className="container comparison-context-grid">
|
||||
<article className="comparison-context-card">
|
||||
<p className="tag">The competitor</p>
|
||||
<h2>{competitor.name} at a glance</h2>
|
||||
<p>{competitor.competitorSnapshot}</p>
|
||||
</article>
|
||||
<article className="comparison-context-card comparison-context-card--accent">
|
||||
<p className="tag">The GreenLens angle</p>
|
||||
<h2>The plant ER, not the encyclopedia.</h2>
|
||||
<p>{competitor.greenLensPositioning}</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-theses">
|
||||
<div className="container">
|
||||
<div className="comparison-section-head">
|
||||
<p className="tag">Core difference</p>
|
||||
<h2>Why users compare these two apps.</h2>
|
||||
</div>
|
||||
|
||||
<div className="comparison-pain-grid">
|
||||
<article className="comparison-pain-card">
|
||||
<h3>Why searchers keep looking</h3>
|
||||
<ul className="comparison-bullet-list comparison-bullet-list--dark">
|
||||
{competitor.whyPeopleCompare.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
{competitor.theses.map((item) => (
|
||||
<article key={item.title} className="comparison-thesis-card">
|
||||
<h3>{item.title}</h3>
|
||||
<div className="comparison-thesis-copy">
|
||||
<div>
|
||||
<p className="comparison-mini-label">GreenLens</p>
|
||||
<p>{item.greenlens}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="comparison-mini-label">{competitor.name}</p>
|
||||
<p>{item.competitor}</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-table-section" id="comparison-table">
|
||||
<div className="container">
|
||||
<div className="comparison-section-head">
|
||||
<p className="tag">At a glance</p>
|
||||
<h2>Where GreenLens and {competitor.name} differ.</h2>
|
||||
</div>
|
||||
|
||||
<div className="comparison-table">
|
||||
<div className="comparison-table-header">
|
||||
<span>Category</span>
|
||||
<span>GreenLens</span>
|
||||
<span>{competitor.name}</span>
|
||||
</div>
|
||||
|
||||
{competitor.categories.map((item) => (
|
||||
<article key={item.title} className="comparison-row">
|
||||
<div className="comparison-row-title">{item.title}</div>
|
||||
<div className="comparison-cell comparison-cell--greenlens">{item.greenlens}</div>
|
||||
<div className="comparison-cell comparison-cell--competitor">{item.competitor}</div>
|
||||
<p className="comparison-row-verdict">{item.whyItMatters}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-fit">
|
||||
<div className="container comparison-fit-grid">
|
||||
<article className="comparison-fit-card comparison-fit-card--greenlens">
|
||||
<p className="tag">Best fit</p>
|
||||
<h2>Choose GreenLens if you need:</h2>
|
||||
<ul className="comparison-bullet-list comparison-bullet-list--dark">
|
||||
{competitor.greenLensBestFor.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article className="comparison-fit-card">
|
||||
<p className="tag">Still a fit</p>
|
||||
<h2>Choose {competitor.name} if you need:</h2>
|
||||
<ul className="comparison-bullet-list comparison-bullet-list--dark">
|
||||
{competitor.competitorBestFor.map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-emergency">
|
||||
<div className="container">
|
||||
<div className="comparison-section-head">
|
||||
<p className="tag">Plant ER scenarios</p>
|
||||
<h2>What this difference looks like in real use.</h2>
|
||||
</div>
|
||||
|
||||
<div className="comparison-scenario-grid">
|
||||
{competitor.emergencyScenarios.map((item) => (
|
||||
<article key={item.symptom} className="comparison-scenario-card">
|
||||
<h3>{item.symptom}</h3>
|
||||
<div className="comparison-scenario-copy">
|
||||
<div>
|
||||
<p className="comparison-mini-label">GreenLens</p>
|
||||
<p>{item.greenlens}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="comparison-mini-label">{competitor.name}</p>
|
||||
<p>{item.competitor}</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-faq">
|
||||
<div className="container">
|
||||
<div className="comparison-section-head">
|
||||
<p className="tag">FAQ</p>
|
||||
<h2>Questions users ask before switching.</h2>
|
||||
</div>
|
||||
|
||||
<div className="comparison-faq-grid">
|
||||
{competitor.faqs.map((item) => (
|
||||
<article key={item.question} className="comparison-faq-card">
|
||||
<h3>{item.question}</h3>
|
||||
<p>{item.answer}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="comparison-links">
|
||||
<div className="container comparison-links-grid">
|
||||
{peers.map((peer) => (
|
||||
<Link key={peer.slug} href={`/vs/${peer.slug}`} className="comparison-link-card">
|
||||
<p className="comparison-mini-label">Compare next</p>
|
||||
<h3>{siteConfig.name} vs {peer.name}</h3>
|
||||
<p>
|
||||
See how GreenLens stacks up against {peer.name} for plant emergencies,
|
||||
diagnosis clarity, and care workflow design.
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<Link href="/support" className="comparison-link-card comparison-link-card--support">
|
||||
<p className="comparison-mini-label">Need more detail?</p>
|
||||
<h3>Talk to GreenLens support</h3>
|
||||
<p>
|
||||
Questions about billing, scans, care plans, or rollout? Use the support page
|
||||
and we will help from there.
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<CTA />
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -31,26 +31,26 @@ const faqs = [
|
||||
},
|
||||
{
|
||||
question: {
|
||||
en: 'Can I use it offline?',
|
||||
de: 'Kann ich die App offline nutzen?',
|
||||
es: 'Puedo usarla sin conexion?'
|
||||
en: 'Can I use GreenLens offline?',
|
||||
de: 'Kann ich GreenLens offline nutzen?',
|
||||
es: 'Puedo usar GreenLens sin conexion?'
|
||||
},
|
||||
answer: {
|
||||
en: 'Some experiences may require a connection, especially for scan-related features. Saved information inside the app can remain available afterward.',
|
||||
de: 'Einige Funktionen benoetigen eine Verbindung, besonders scanbezogene Features. Gespeicherte Informationen in der App koennen danach weiter verfuegbar bleiben.',
|
||||
es: 'Algunas funciones requieren conexion, especialmente las relacionadas con escaneos. La informacion guardada puede seguir disponible despues.'
|
||||
en: 'Plant identification and health checks require an internet connection. Your saved collection, care notes, and watering reminders are available offline.',
|
||||
de: 'Pflanzenidentifikation und Gesundheitscheck benoetigen eine Internetverbindung. Deine gespeicherte Sammlung, Pflegenotizen und Giess-Erinnerungen sind offline verfuegbar.',
|
||||
es: 'La identificacion de plantas y el control de salud requieren conexion a internet. Tu coleccion guardada, notas de cuidado y recordatorios de riego estan disponibles sin conexion.'
|
||||
}
|
||||
},
|
||||
{
|
||||
question: {
|
||||
en: 'What kind of plants can I use it for?',
|
||||
de: 'Fuer welche Pflanzen kann ich die App nutzen?',
|
||||
es: 'Para que tipo de plantas puedo usar la app?'
|
||||
en: 'What kind of plants can I use GreenLens for?',
|
||||
de: 'Fuer welche Pflanzen kann ich GreenLens nutzen?',
|
||||
es: 'Para que tipo de plantas puedo usar GreenLens?'
|
||||
},
|
||||
answer: {
|
||||
en: 'GreenLens is built for everyday plant owners who want help with houseplants, garden plants, and general care questions.',
|
||||
de: 'GreenLens richtet sich an Pflanzenbesitzer, die Hilfe bei Zimmerpflanzen, Gartenpflanzen und allgemeinen Pflegefragen wollen.',
|
||||
es: 'GreenLens esta pensada para personas que quieren ayuda con plantas de interior, jardin y preguntas generales de cuidado.'
|
||||
en: 'GreenLens covers 450+ plant species including houseplants, garden plants, and succulents. It is built for everyday plant owners who want identification and care guidance in one place.',
|
||||
de: 'GreenLens umfasst ueber 450 Pflanzenarten, darunter Zimmerpflanzen, Gartenpflanzen und Sukkulenten. Die App richtet sich an Pflanzenbesitzer, die Identifikation und Pflege an einem Ort wollen.',
|
||||
es: 'GreenLens cubre mas de 450 especies de plantas, incluyendo plantas de interior, de jardin y suculentas. Esta pensada para quienes quieren identificacion y cuidado en un solo lugar.'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -27,14 +27,20 @@ export default function Footer() {
|
||||
{t.footer.cols.map((col, ci) => (
|
||||
<div className="footer-col" key={col.title}>
|
||||
<div className="footer-col-title">{col.title}</div>
|
||||
{col.links.map((label, li) => (
|
||||
<Link key={label} href={LINK_HREFS[ci]?.[li] ?? '/support'}>
|
||||
{label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{col.links.map((label, li) => (
|
||||
<Link key={label} href={LINK_HREFS[ci]?.[li] ?? '/support'}>
|
||||
{label}
|
||||
</Link>
|
||||
))}
|
||||
{ci === 1 && (
|
||||
<>
|
||||
<Link href="/vs/picturethis">GreenLens vs PictureThis</Link>
|
||||
<Link href="/vs/plantum">GreenLens vs Plantum</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="footer-brand-xl" aria-hidden="true">GREENLENS</div>
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ export default function Hero() {
|
||||
<div className="hero-visual reveal-fade delay-2">
|
||||
<div className="hero-video-card hero-video-16-9">
|
||||
<video autoPlay loop muted playsInline aria-label="GreenLens App Demo">
|
||||
<source src="/GreenLensHype.mp4" type="video/mp4" />
|
||||
<source src="/greenlens.mp4" type="video/mp4" />
|
||||
</video>
|
||||
<div className="hero-video-card-overlay" />
|
||||
<div className="hero-video-badge">
|
||||
|
||||
384
greenlns-landing/lib/competitors.ts
Normal file
384
greenlns-landing/lib/competitors.ts
Normal file
@@ -0,0 +1,384 @@
|
||||
export type CompetitorSlug = 'picturethis' | 'plantum'
|
||||
|
||||
export interface ComparisonThesis {
|
||||
title: string
|
||||
greenlens: string
|
||||
competitor: string
|
||||
}
|
||||
|
||||
export interface ComparisonCategory {
|
||||
title: string
|
||||
greenlens: string
|
||||
competitor: string
|
||||
whyItMatters: string
|
||||
}
|
||||
|
||||
export interface EmergencyScenario {
|
||||
symptom: string
|
||||
greenlens: string
|
||||
competitor: string
|
||||
}
|
||||
|
||||
export interface ComparisonFaq {
|
||||
question: string
|
||||
answer: string
|
||||
}
|
||||
|
||||
export interface CompetitorProfile {
|
||||
slug: CompetitorSlug
|
||||
name: string
|
||||
metaTitle: string
|
||||
metaDescription: string
|
||||
heroSummary: string
|
||||
heroVerdict: string[]
|
||||
disclaimer: string
|
||||
lastVerified: string
|
||||
competitorSnapshot: string
|
||||
greenLensPositioning: string
|
||||
whyPeopleCompare: string[]
|
||||
theses: ComparisonThesis[]
|
||||
categories: ComparisonCategory[]
|
||||
greenLensBestFor: string[]
|
||||
competitorBestFor: string[]
|
||||
emergencyScenarios: EmergencyScenario[]
|
||||
faqs: ComparisonFaq[]
|
||||
}
|
||||
|
||||
export const competitorProfiles: Record<CompetitorSlug, CompetitorProfile> = {
|
||||
picturethis: {
|
||||
slug: 'picturethis',
|
||||
name: 'PictureThis',
|
||||
metaTitle: 'GreenLens vs PictureThis',
|
||||
metaDescription:
|
||||
'Compare GreenLens vs PictureThis for plant emergencies, next-step diagnosis, pricing friction, and care guidance. See when GreenLens is the better fit.',
|
||||
heroSummary:
|
||||
'PictureThis is one of the best-known plant ID apps on the market, but GreenLens is built for a different moment: when your plant already looks wrong and you need the next correct action, not another generic care checklist.',
|
||||
heroVerdict: [
|
||||
'Choose GreenLens if your real question is what to do next about yellow leaves, soft stems, or a sudden decline.',
|
||||
'Choose PictureThis if your priority is broad plant identification and a large reference library first.',
|
||||
'Do not assume a rigid watering calendar is safer. For stressed plants, that habit often creates the next mistake.',
|
||||
],
|
||||
disclaimer:
|
||||
'Pricing, trials, and feature gates can change by market and over time. This page reflects the current research summary used for GreenLens landing content.',
|
||||
lastVerified: 'April 10, 2026',
|
||||
competitorSnapshot:
|
||||
'PictureThis is the category leader for mainstream plant ID. It is commonly associated with a large botanical database, fast scan-to-name results, and an aggressive subscription flow that many users describe as frustrating during onboarding.',
|
||||
greenLensPositioning:
|
||||
'GreenLens is the plant ER angle: situational triage, calmer next-step guidance, and a clearer path from symptom to action when a plant suddenly starts struggling.',
|
||||
whyPeopleCompare: [
|
||||
'They can identify a plant, but still do not know what to do after the scan.',
|
||||
'They want help with emergencies, not just an encyclopedia in their pocket.',
|
||||
'They are tired of paywall pressure before they feel confident about the diagnosis.',
|
||||
],
|
||||
theses: [
|
||||
{
|
||||
title: 'Subscription pressure vs calmer triage',
|
||||
greenlens:
|
||||
'GreenLens is positioned to get users to the situation first and the decision second, without making the panic moment feel like a billing funnel.',
|
||||
competitor:
|
||||
'PictureThis is widely known for aggressive paywalls and hard-to-dismiss upgrade prompts before trust is fully earned.',
|
||||
},
|
||||
{
|
||||
title: 'Calendar reminders vs situational judgment',
|
||||
greenlens:
|
||||
'GreenLens frames care around what changed, what the soil feels like, and what happened in the last 14 days.',
|
||||
competitor:
|
||||
'PictureThis leans on scheduled care reminders that can encourage overwatering when symptoms are misread.',
|
||||
},
|
||||
{
|
||||
title: 'Generic suggestions vs the next right step',
|
||||
greenlens:
|
||||
'GreenLens focuses on one clear next move: check the soil, stop fertilizing, review the recent change, or isolate the cause.',
|
||||
competitor:
|
||||
'PictureThis disease and health guidance often lands on broad advice such as more light or more fertilizer, even when the user needs sharper triage.',
|
||||
},
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
title: 'Plant emergencies',
|
||||
greenlens:
|
||||
'Built around fast triage for visible problems like yellow leaves, mushy stems, droop after repotting, or sudden decline.',
|
||||
competitor:
|
||||
'Strong at telling you what the plant is, less convincing when the real problem is deciding the safest next intervention.',
|
||||
whyItMatters:
|
||||
'A stressed plant does not need more content. It needs the next low-risk action that prevents the owner from making things worse.',
|
||||
},
|
||||
{
|
||||
title: 'Identification and plant database',
|
||||
greenlens:
|
||||
'Useful when identification is part of the rescue flow, but not positioned as the largest encyclopedia in the category.',
|
||||
competitor:
|
||||
'This is the core PictureThis strength: broad species coverage and fast recognition backed by a very large library.',
|
||||
whyItMatters:
|
||||
'If naming the plant is the end goal, PictureThis is strong. If naming the plant is just step one, GreenLens has a clearer story.',
|
||||
},
|
||||
{
|
||||
title: 'Care philosophy',
|
||||
greenlens:
|
||||
'Situational care. The app should ask what changed recently and whether the soil or environment actually supports the next move.',
|
||||
competitor:
|
||||
'Calendar-driven care plans and reminders that can feel tidy, but often miss the context that matters most for beginners.',
|
||||
whyItMatters:
|
||||
'Strict calendars are one of the easiest ways to overwater a plant that already shows stress.',
|
||||
},
|
||||
{
|
||||
title: 'Diagnosis output',
|
||||
greenlens:
|
||||
'Prioritizes a smaller number of concrete interventions with clearer sequencing and less noise.',
|
||||
competitor:
|
||||
'Often returns generic advice that sounds plausible but does not reduce uncertainty enough for first-time plant owners.',
|
||||
whyItMatters:
|
||||
'The user is not buying a list of possibilities. They are trying to avoid the wrong action today.',
|
||||
},
|
||||
{
|
||||
title: 'Pricing and trust',
|
||||
greenlens:
|
||||
'Paid features still exist, but the brand story is fairer and more transparent than hiding the choice behind manipulative UI.',
|
||||
competitor:
|
||||
'PictureThis is frequently criticized for paywall-first moments, especially around trials and dismiss states.',
|
||||
whyItMatters:
|
||||
'Trust matters more when someone is already anxious about killing a plant.',
|
||||
},
|
||||
{
|
||||
title: 'Beginner clarity',
|
||||
greenlens:
|
||||
'Designed to calm the situation down and turn a messy symptom into a single next step.',
|
||||
competitor:
|
||||
'The app gives users a lot of information quickly, which is helpful for reference and less helpful for triage.',
|
||||
whyItMatters:
|
||||
'Beginners rarely need more detail first. They need a better decision path.',
|
||||
},
|
||||
],
|
||||
greenLensBestFor: [
|
||||
'People dealing with a plant that looks wrong right now and want the safest next step.',
|
||||
'Beginners who need triage, not a full plant encyclopedia.',
|
||||
'Users who distrust manipulative subscription flows and want clearer product positioning.',
|
||||
],
|
||||
competitorBestFor: [
|
||||
'Users who mainly want broad plant identification from a very large reference database.',
|
||||
'People who enjoy an all-purpose plant encyclopedia and do not mind more aggressive upsell patterns.',
|
||||
'Plant owners whose first question is what the plant is, not how to stabilize it.',
|
||||
],
|
||||
emergencyScenarios: [
|
||||
{
|
||||
symptom: 'Yellow leaves after a recent move',
|
||||
greenlens:
|
||||
'GreenLens frames the issue around the recent change, environment shift, and whether watering behavior also changed.',
|
||||
competitor:
|
||||
'PictureThis may still identify the plant correctly, but the next-step guidance is more likely to stay broad and less situational.',
|
||||
},
|
||||
{
|
||||
symptom: 'Soft stems or signs of overwatering',
|
||||
greenlens:
|
||||
'GreenLens emphasizes checking moisture and stopping instinctive “care stacking” before adding fertilizer or another routine task.',
|
||||
competitor:
|
||||
'A calendar-driven reminder model can push users toward the exact behavior that created the problem.',
|
||||
},
|
||||
{
|
||||
symptom: 'Sudden decline with unclear cause',
|
||||
greenlens:
|
||||
'GreenLens narrows the response to the next safest action instead of overwhelming the user with a long diagnosis tree.',
|
||||
competitor:
|
||||
'PictureThis is more useful as a reference layer than as a focused emergency workflow.',
|
||||
},
|
||||
],
|
||||
faqs: [
|
||||
{
|
||||
question: 'Is GreenLens more accurate than PictureThis for plant identification?',
|
||||
answer:
|
||||
'GreenLens does not need to win the encyclopedia race to be the better choice in a plant emergency. PictureThis is still stronger if broad ID coverage is your main requirement. GreenLens is stronger when the real job is choosing the next action after the scan.',
|
||||
},
|
||||
{
|
||||
question: 'Why compare GreenLens and PictureThis if both use AI?',
|
||||
answer:
|
||||
'Because they optimize for different outcomes. PictureThis is strongest as a mainstream identification and reference app. GreenLens is framed around triage, situational care decisions, and calmer guidance when something is already going wrong.',
|
||||
},
|
||||
{
|
||||
question: 'Does GreenLens replace watering calendars?',
|
||||
answer:
|
||||
'It replaces the idea that a calendar alone is enough. GreenLens emphasizes what changed, what the soil feels like, and whether a plant is showing stress before another routine task is triggered.',
|
||||
},
|
||||
{
|
||||
question: 'Does GreenLens also have paid features?',
|
||||
answer:
|
||||
'Yes. GreenLens includes paid functionality such as subscriptions and AI-related credits. The difference in this comparison is the positioning: the diagnosis moment should feel clearer and fairer, not like a hidden-dismiss billing trap.',
|
||||
},
|
||||
],
|
||||
},
|
||||
plantum: {
|
||||
slug: 'plantum',
|
||||
name: 'Plantum',
|
||||
metaTitle: 'GreenLens vs Plantum',
|
||||
metaDescription:
|
||||
'Compare GreenLens vs Plantum for plant diagnosis, care workflows, pricing friction, and beginner clarity. See why GreenLens is the better plant ER choice.',
|
||||
heroSummary:
|
||||
'Plantum markets itself as a high-accuracy, all-in-one plant care assistant. GreenLens is the sharper choice when the user does not want an all-in-one system right now, but a clear answer to what to do next for a struggling plant.',
|
||||
heroVerdict: [
|
||||
'Choose GreenLens if you want triage, not another stack of care hacks and tasks.',
|
||||
'Choose Plantum if you want a broader all-in-one assistant with more expansive care reporting.',
|
||||
'If the plant is already in trouble, clarity beats completeness.',
|
||||
],
|
||||
disclaimer:
|
||||
'Pricing, feature limits, and diagnosis depth can change by region and plan. This page reflects the current research summary used for GreenLens landing content.',
|
||||
lastVerified: 'April 10, 2026',
|
||||
competitorSnapshot:
|
||||
'Plantum, formerly NatureID, competes on AI precision, plant disease reports, and the promise of being a full care assistant. It often looks more detailed than GreenLens at first glance, but that detail can turn into checklist overload for beginners.',
|
||||
greenLensPositioning:
|
||||
'GreenLens is the anti-actionism option: diagnose the situation, reduce noise, and recommend the next lowest-risk step instead of flooding the user with tasks.',
|
||||
whyPeopleCompare: [
|
||||
'They want help with a sick plant but do not want to decode a long report.',
|
||||
'They are looking for a realistic alternative to rigid plant journals and task stacks.',
|
||||
'They want a tool that helps them decide, not just one that generates more plant-care output.',
|
||||
],
|
||||
theses: [
|
||||
{
|
||||
title: 'Actionism vs next-step clarity',
|
||||
greenlens:
|
||||
'GreenLens reduces the problem to the next clear intervention instead of rewarding users with a longer checklist.',
|
||||
competitor:
|
||||
'Plantum can feel thorough, but the volume of advice often creates urgency and overreaction rather than confidence.',
|
||||
},
|
||||
{
|
||||
title: 'Plant ER vs all-in-one care assistant',
|
||||
greenlens:
|
||||
'GreenLens is strongest when the user is already worried and needs triage first.',
|
||||
competitor:
|
||||
'Plantum is built as a broad assistant with journals, tasks, and deeper care material around each plant.',
|
||||
},
|
||||
{
|
||||
title: 'Situational care vs rigid task systems',
|
||||
greenlens:
|
||||
'GreenLens emphasizes recent change, soil condition, and symptom severity over routine schedules.',
|
||||
competitor:
|
||||
'Plantum still leans on structured care workflows that can miss whether the current advice matches the actual state of the plant.',
|
||||
},
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
title: 'Diagnosis depth',
|
||||
greenlens:
|
||||
'GreenLens goes narrower and sharper: fewer steps, stronger sequencing, more focus on what to do now.',
|
||||
competitor:
|
||||
'Plantum often presents a more detailed health report and a denser care framework around the diagnosis.',
|
||||
whyItMatters:
|
||||
'Detail can look impressive while still failing the anxious beginner who needs one confident decision.',
|
||||
},
|
||||
{
|
||||
title: 'Beginner usability',
|
||||
greenlens:
|
||||
'Built to calm the situation down and reduce the chance of stacking too many fixes at once.',
|
||||
competitor:
|
||||
'Plantum can overwhelm newer plant owners with too many care hacks, checks, and supporting explanations.',
|
||||
whyItMatters:
|
||||
'In plant care, too many “helpful” tasks often create the next error.',
|
||||
},
|
||||
{
|
||||
title: 'Care tracking model',
|
||||
greenlens:
|
||||
'GreenLens frames care around evidence from the plant and the recent environment, not routine by default.',
|
||||
competitor:
|
||||
'Plantum includes journals and care tasks, but the structure still tends to pull users into predefined care systems.',
|
||||
whyItMatters:
|
||||
'A system is only useful if it matches the current state of the plant.',
|
||||
},
|
||||
{
|
||||
title: 'Pricing friction',
|
||||
greenlens:
|
||||
'GreenLens can still monetize advanced AI help, but the value story is clarity and fairness at the decision point.',
|
||||
competitor:
|
||||
'Plantum typically gates deeper diagnosis and larger plant management needs behind subscription pressure.',
|
||||
whyItMatters:
|
||||
'People comparing alternatives often feel they are paying for complexity before they see clear help.',
|
||||
},
|
||||
{
|
||||
title: 'Plant identification',
|
||||
greenlens:
|
||||
'Identification supports the diagnosis flow, but GreenLens is not positioned as the broadest species database.',
|
||||
competitor:
|
||||
'Plantum markets strong identification depth, often with claims around tens of thousands of species and very high accuracy.',
|
||||
whyItMatters:
|
||||
'If you mainly want a broad AI plant assistant, Plantum stays credible. If you need triage, GreenLens is easier to justify.',
|
||||
},
|
||||
{
|
||||
title: 'Outcome for stressed plants',
|
||||
greenlens:
|
||||
'The product story is built around the next right move: inspect moisture, review the last change, and avoid reactive care stacking.',
|
||||
competitor:
|
||||
'Plantum can generate a more comprehensive response, but not always a more usable one under stress.',
|
||||
whyItMatters:
|
||||
'The best care plan is the one a worried beginner can actually follow correctly.',
|
||||
},
|
||||
],
|
||||
greenLensBestFor: [
|
||||
'Plant owners who want a practical rescue workflow instead of a bigger care system.',
|
||||
'Beginners who get overwhelmed by long disease reports and plant-care checklists.',
|
||||
'Users who care more about the next safe action than a full assistant dashboard.',
|
||||
],
|
||||
competitorBestFor: [
|
||||
'Users who want a richer all-in-one plant assistant with more structured care content.',
|
||||
'People who are comfortable interpreting longer reports and broader care workflows.',
|
||||
'Plant owners who want journals, tasks, and a deeper “care assistant” feel around every plant.',
|
||||
],
|
||||
emergencyScenarios: [
|
||||
{
|
||||
symptom: 'Yellow leaves with no obvious cause',
|
||||
greenlens:
|
||||
'GreenLens narrows the response to what changed recently and what the safest next check is before the user starts “doing more.”',
|
||||
competitor:
|
||||
'Plantum is more likely to send the user into a broader diagnostic and care framework that feels complete but slower to act on.',
|
||||
},
|
||||
{
|
||||
symptom: 'Soft stems or soggy soil',
|
||||
greenlens:
|
||||
'GreenLens keeps the focus on stopping the wrong behavior first instead of layering more plant-care tasks on top.',
|
||||
competitor:
|
||||
'Plantum can provide extensive advice, but more depth is not always better when the likely issue is already over-care.',
|
||||
},
|
||||
{
|
||||
symptom: 'Multiple symptoms after a repot or environment shift',
|
||||
greenlens:
|
||||
'GreenLens frames the situation around the recent change event and next low-risk step.',
|
||||
competitor:
|
||||
'Plantum offers more reporting, but that can still leave the user deciding among too many actions at once.',
|
||||
},
|
||||
],
|
||||
faqs: [
|
||||
{
|
||||
question: 'Is GreenLens less powerful than Plantum because it is simpler?',
|
||||
answer:
|
||||
'Not for the job GreenLens is trying to do. Plantum offers a wider assistant model. GreenLens intentionally narrows the workflow so a stressed plant owner gets to the next decision faster.',
|
||||
},
|
||||
{
|
||||
question: 'Who should still choose Plantum over GreenLens?',
|
||||
answer:
|
||||
'Choose Plantum if you want a more expansive all-in-one care assistant, broader reporting, and a more structured plant-management experience around each plant.',
|
||||
},
|
||||
{
|
||||
question: 'Why does GreenLens emphasize triage instead of full care plans first?',
|
||||
answer:
|
||||
'Because the biggest beginner mistake is often reacting too fast with too many fixes. GreenLens is designed to reduce that risk by sequencing the next step more clearly.',
|
||||
},
|
||||
{
|
||||
question: 'Does GreenLens ignore long-term care tracking?',
|
||||
answer:
|
||||
'No. GreenLens still supports ongoing care and collection management. The difference is that the comparison pages prioritize its emergency and decision-support value over the promise of being an all-in-one assistant for everything.',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export const competitorOrder: CompetitorSlug[] = ['picturethis', 'plantum']
|
||||
|
||||
export function getCompetitorBySlug(slug: string): CompetitorProfile | undefined {
|
||||
if (slug === 'picturethis' || slug === 'plantum') {
|
||||
return competitorProfiles[slug]
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function getPeerCompetitors(currentSlug: CompetitorSlug): CompetitorProfile[] {
|
||||
return competitorOrder
|
||||
.filter((slug) => slug !== currentSlug)
|
||||
.map((slug) => competitorProfiles[slug])
|
||||
}
|
||||
@@ -41,7 +41,7 @@ export const translations = {
|
||||
tag: 'Features',
|
||||
h2a: 'Alles, was dein',
|
||||
h2b: 'Urban Jungle braucht.',
|
||||
desc: 'Von der ersten Identifikation bis zur laufenden Pflege hilft GreenLens dir, Pflanzen besser zu verstehen und besser zu organisieren.',
|
||||
desc: 'Von der ersten Identifikation bis zur laufenden Pflege hilft GreenLens dir, Pflanzen besser zu verstehen und besser zu organisieren. Das Lexikon umfasst ueber 450 Pflanzenarten.',
|
||||
},
|
||||
cta: {
|
||||
tag: 'Download',
|
||||
@@ -107,7 +107,7 @@ export const translations = {
|
||||
tag: 'Features',
|
||||
h2a: 'Everything your',
|
||||
h2b: 'Urban Jungle needs.',
|
||||
desc: 'From first identification to ongoing care, GreenLens helps you understand plants better and stay organized.',
|
||||
desc: 'From first identification to ongoing care, GreenLens helps you understand plants better and stay organized. The lexicon covers 450+ plant species.',
|
||||
},
|
||||
cta: {
|
||||
tag: 'Download',
|
||||
@@ -173,7 +173,7 @@ export const translations = {
|
||||
tag: 'Funciones',
|
||||
h2a: 'Todo lo que tu',
|
||||
h2b: 'jardin urbano necesita.',
|
||||
desc: 'Desde la primera identificacion hasta el cuidado continuo, GreenLens te ayuda a entender mejor tus plantas y a organizarte.',
|
||||
desc: 'Desde la primera identificacion hasta el cuidado continuo, GreenLens te ayuda a entender mejor tus plantas y a organizarte. El lexico cubre mas de 450 especies de plantas.',
|
||||
},
|
||||
cta: {
|
||||
tag: 'Descarga',
|
||||
|
||||
@@ -3,9 +3,6 @@ import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: 'standalone',
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
turbopack: {
|
||||
root: path.join(__dirname),
|
||||
},
|
||||
|
||||
85
keyword-research.csv
Normal file
85
keyword-research.csv
Normal file
@@ -0,0 +1,85 @@
|
||||
Cluster;Keyword;Suchanfragen/Monat;Trend 3M;Trend YoY;Wettbewerb;CPC Min (€);CPC Max (€);Typ
|
||||
Plant Identification;plant identifier app;10.000-100.000;0%;0%;Mittel;0,62;2,58;Eingabe
|
||||
Plant Identification;identify plants by photo;10.000-100.000;+900%;+900%;Mittel;0,44;1,56;Eingabe
|
||||
Plant Identification;plant recognition app;10.000-100.000;0%;0%;Mittel;0,62;2,58;Eingabe
|
||||
Plant Identification;identify plant from picture;10.000-100.000;+900%;+900%;Mittel;0,44;1,56;Eingabe
|
||||
Plant Identification;plant scanner app;100-1.000;0%;0%;Mittel;1,03;3,99;Eingabe
|
||||
Plant Identification;plant id app;10.000-100.000;0%;0%;Mittel;0,62;2,58;Eingabe
|
||||
Plant Identification;free plant identifier app;10.000-100.000;+900%;0%;Mittel;0,32;1,25;Idee
|
||||
Plant Identification;plant app;1.000-10.000;0%;-90%;Mittel;1,14;3,78;Idee
|
||||
Plant Identification;plant identifier free;10.000-100.000;0%;0%;Mittel;0,41;1,49;Idee
|
||||
Plant Identification;free plant identifier;1.000-10.000;0%;0%;Mittel;0,32;1,07;Idee
|
||||
Plant Identification;free plant identification app;1.000-10.000;0%;0%;Mittel;0,27;1,08;Idee
|
||||
Plant Identification;app to identify plants;10.000-100.000;0%;0%;Mittel;0,62;2,58;Idee
|
||||
Plant Identification;tree identification app;10.000-100.000;0%;0%;Mittel;0,58;2,28;Idee
|
||||
Plant Identification;plant diagnosis app;1.000-10.000;0%;0%;Hoch;1,63;5,22;Idee
|
||||
Plant Identification;plant app free;1.000-10.000;0%;0%;Hoch;0,70;2,64;Idee
|
||||
Plant Identification;plant identifier;100.000-1.000.000;0%;-90%;Mittel;0,55;1,83;Idee
|
||||
Plant Care;plant care app;1.000-10.000;0%;0%;Mittel;1,28;3,78;Eingabe
|
||||
Plant Care;houseplant care app;10-100;0%;+900%;Mittel;1,30;3,59;Eingabe
|
||||
Plant Care;plant watering reminder;100-1.000;0%;0%;Hoch;0,45;1,77;Eingabe
|
||||
Plant Care;plant care tracker;10-100;0%;0%;Hoch;1,38;4,40;Eingabe
|
||||
Plant Care;plant care;1.000-10.000;0%;-90%;Gering;0,81;2,35;Eingabe
|
||||
Plant Care;plant care planner;10-100;0%;0%;Hoch;;;Eingabe
|
||||
Plant Care;indoor plant care app;10-100;0%;0%;Gering;0,98;3,70;Eingabe
|
||||
Plant Care;plant watering app;100-1.000;0%;0%;Mittel;1,00;2,65;Eingabe
|
||||
Plant Care;plant care reminder app;10-100;0%;0%;Gering;0,75;3,03;Eingabe
|
||||
Plant Health;plant disease identifier;1.000-10.000;+900%;0%;Mittel;0,95;3,04;Eingabe
|
||||
Plant Health;plant health checker;100-1.000;0%;-90%;Hoch;0,77;2,16;Eingabe
|
||||
Plant Health;sick plant diagnosis;100-1.000;0%;-90%;Hoch;0,97;3,23;Eingabe
|
||||
Plant Health;plant disease app;100-1.000;0%;0%;Gering;0,99;3,53;Eingabe
|
||||
Plant Health;brown leaves;1.000-10.000;0%;0%;Gering;0,86;2,33;Eingabe
|
||||
Plant Health;plant leaves turning yellow;1.000-10.000;0%;0%;Gering;0,03;2,44;Eingabe
|
||||
Plant Health;plant problem diagnosis;100-1.000;0%;-90%;Mittel;0,95;3,80;Eingabe
|
||||
Plant Health;plant health app;1.000-10.000;0%;0%;Hoch;1,49;4,73;Eingabe
|
||||
Plant Health;pest identification;100-1.000;0%;0%;Gering;0,73;7,76;Eingabe
|
||||
Deutsche Keywords;pflanzen erkennen app;1.000-10.000;0%;0%;Mittel;0,13;0,74;Eingabe
|
||||
Deutsche Keywords;pflanzenerkennung app;1.000-10.000;+900%;0%;Mittel;0,12;0,66;Eingabe
|
||||
Deutsche Keywords;pflanzen bestimmen app;1.000-10.000;+900%;0%;Mittel;0,11;0,68;Eingabe
|
||||
Deutsche Keywords;pflanzen app;1.000-10.000;0%;0%;Mittel;0,22;1,03;Eingabe
|
||||
Deutsche Keywords;zimmerpflanzen;10.000-100.000;0%;0%;Hoch;0,15;0,51;Eingabe
|
||||
Deutsche Keywords;pflanzen scanner app;100-1.000;+900%;0%;Mittel;0,26;1,27;Eingabe
|
||||
Deutsche Keywords;pflanzen identifizieren app;100-1.000;+900%;0%;Mittel;0,17;0,83;Eingabe
|
||||
Collection & Tracking;plant collection app;10-100;0%;0%;Gering;0,82;2,65;Eingabe
|
||||
Collection & Tracking;track plant growth;10-100;0%;0%;Gering;;;Eingabe
|
||||
Collection & Tracking;plant journal app;10-100;0%;0%;Mittel;0,80;2,09;Eingabe
|
||||
Collection & Tracking;plant tracker app;100-1.000;0%;0%;Gering;1,16;2,93;Eingabe
|
||||
Collection & Tracking;houseplant tracker;10-100;0%;0%;Gering;;;Eingabe
|
||||
Collection & Tracking;plant diary app;10-100;0%;0%;Gering;0,57;1,70;Eingabe
|
||||
Collection & Tracking;plant log app;10-100;0%;0%;Mittel;0,86;2,94;Eingabe
|
||||
Collection & Tracking;plant management app;10-100;0%;0%;Mittel;1,09;2,20;Eingabe
|
||||
Collection & Tracking;plant growth journal;10-100;0%;0%;Mittel;;;Eingabe
|
||||
Competitor Alternatives;picturethis alternative;10-100;0%;0%;Gering;0,18;1,30;Eingabe
|
||||
Competitor Alternatives;plantnet alternative;10-100;0%;0%;Mittel;;;Eingabe
|
||||
Competitor Alternatives;best plant identification app;1.000-10.000;0%;0%;Mittel;0,92;3,35;Eingabe
|
||||
Competitor Alternatives;plant identifier free;10.000-100.000;0%;0%;Mittel;0,41;1,49;Eingabe
|
||||
Competitor Alternatives;plant scanner free;100-1.000;0%;0%;Hoch;0,69;2,69;Eingabe
|
||||
Competitor Alternatives;plant recognition free;10-100;0%;0%;Hoch;0,21;0,55;Eingabe
|
||||
Competitor Alternatives;plant id free app;100-1.000;0%;0%;Mittel;0,28;1,16;Eingabe
|
||||
Competitor Alternatives;inaturalist;10.000-100.000;+900%;+900%;Gering;0,30;1,03;Eingabe
|
||||
Urban Jungle & Indoor;urban jungle app;10-100;0%;0%;Gering;;;Eingabe
|
||||
Urban Jungle & Indoor;indoor plant app;100-1.000;0%;0%;Hoch;1,24;3,83;Eingabe
|
||||
Urban Jungle & Indoor;houseplant app;100-1.000;0%;0%;Mittel;1,13;3,25;Eingabe
|
||||
Urban Jungle & Indoor;indoor gardening app;10-100;0%;0%;Mittel;;;Eingabe
|
||||
Urban Jungle & Indoor;succulent care app;10-100;0%;0%;Gering;;;Eingabe
|
||||
Urban Jungle & Indoor;fiddle leaf fig;10.000-100.000;0%;0%;Hoch;0,03;0,91;Eingabe
|
||||
iOS & App Store;plant app iphone;10-100;0%;0%;Gering;1,45;3,89;Eingabe
|
||||
iOS & App Store;plant app ios;10-100;0%;0%;Mittel;;;Eingabe
|
||||
iOS & App Store;best plant app for iphone;10-100;0%;-90%;Mittel;1,20;3,06;Eingabe
|
||||
iOS & App Store;plant identifier iphone;100-1.000;0%;0%;Mittel;0,43;1,27;Eingabe
|
||||
iOS & App Store;plant scanner iphone;10-100;0%;0%;Hoch;;;Eingabe
|
||||
iOS & App Store;gardening app iphone;10-100;0%;0%;Mittel;0,65;2,28;Eingabe
|
||||
AI & Technology;ai plant identifier;1.000-10.000;0%;0%;Mittel;0,65;2,22;Eingabe
|
||||
AI & Technology;ai plant recognition;10-100;0%;0%;Mittel;0,40;2,00;Eingabe
|
||||
AI & Technology;ai plant care;10-100;0%;0%;Mittel;0,71;2,45;Eingabe
|
||||
AI & Technology;plant id;100.000-1.000.000;0%;-90%;Mittel;0,55;1,83;Eingabe
|
||||
AI & Technology;smart plant care;10-100;0%;0%;Hoch;0,51;1,71;Eingabe
|
||||
AI & Technology;plant ai app;100-1.000;0%;0%;Mittel;0,88;3,31;Eingabe
|
||||
Spanish Keywords;identificar plantas app;10-100;0%;0%;Mittel;0,13;0,81;Eingabe
|
||||
Spanish Keywords;app para identificar plantas;100-1.000;0%;0%;Mittel;0,07;0,77;Eingabe
|
||||
Spanish Keywords;cuidado de plantas app;10-100;0%;0%;Gering;0,03;0,22;Eingabe
|
||||
Spanish Keywords;identificador de plantas;1.000-10.000;+900%;0%;Mittel;0,06;0,39;Eingabe
|
||||
Spanish Keywords;app plantas gratis;100-1.000;0%;0%;Mittel;0,08;0,50;Eingabe
|
||||
Spanish Keywords;cuidado plantas interior;10-100;0%;-90%;Hoch;0,15;0,88;Eingabe
|
||||
Spanish Keywords;app jardinería;10-100;0%;0%;Gering;0,22;0,75;Eingabe
|
||||
Spanish Keywords;identificar planta foto;10-100;0%;0%;Gering;;;Eingabe
|
||||
|
Reference in New Issue
Block a user