From 30cfdc0d0ca793becbe4c96c40e9c56751e7263d Mon Sep 17 00:00:00 2001 From: Joao Morais Date: Wed, 4 Feb 2026 14:04:52 -0800 Subject: [PATCH 1/5] add web-vitals --- website/app/components/WebVitals.tsx | 29 ++++++++++++++++++++++++++++ website/app/layout.tsx | 2 ++ website/package.json | 3 ++- website/pnpm-lock.yaml | 8 ++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 website/app/components/WebVitals.tsx diff --git a/website/app/components/WebVitals.tsx b/website/app/components/WebVitals.tsx new file mode 100644 index 0000000..5d73048 --- /dev/null +++ b/website/app/components/WebVitals.tsx @@ -0,0 +1,29 @@ +"use client"; + +import { useEffect } from "react"; +import { onCLS, onINP, onLCP, onFCP, onTTFB, type Metric } from "web-vitals"; + +function sendToAnalytics(metric: Metric) { + // Log in development + if (process.env.NODE_ENV === "development") { + console.log(`[Web Vitals] ${metric.name}:`, metric.value.toFixed(2), metric.rating); + } + + // TODO: Send to your analytics backend + // Examples: + // - Google Analytics: gtag('event', metric.name, { value: metric.value, ... }) + // - Custom endpoint: fetch('/api/vitals', { method: 'POST', body: JSON.stringify(metric) }) + // - Plausible: plausible(metric.name, { props: { value: metric.value } }) +} + +export function WebVitals() { + useEffect(() => { + onCLS(sendToAnalytics); + onINP(sendToAnalytics); + onLCP(sendToAnalytics); + onFCP(sendToAnalytics); + onTTFB(sendToAnalytics); + }, []); + + return null; +} diff --git a/website/app/layout.tsx b/website/app/layout.tsx index b9551b4..7a740d2 100644 --- a/website/app/layout.tsx +++ b/website/app/layout.tsx @@ -4,6 +4,7 @@ import { ClerkProvider } from "@clerk/nextjs"; import ConditionalNavbar from "./components/ConditionalNavbar"; import PageWrapper from "./components/PageWrapper"; import { ThemeProvider } from "./contexts/ThemeContext"; +import { WebVitals } from "./components/WebVitals"; export const metadata: Metadata = { title: "AutoClaw — Deploy OpenClaw in Minutes", @@ -83,6 +84,7 @@ export default function RootLayout({ > + {children} diff --git a/website/package.json b/website/package.json index 6f9be44..b92f374 100644 --- a/website/package.json +++ b/website/package.json @@ -16,7 +16,8 @@ "next": "^16.1.6", "react": "19.1.0", "react-dom": "19.1.0", - "react-markdown": "^10.1.0" + "react-markdown": "^10.1.0", + "web-vitals": "^5.1.0" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/website/pnpm-lock.yaml b/website/pnpm-lock.yaml index 1f97c30..c5a30cb 100644 --- a/website/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: react-markdown: specifier: ^10.1.0 version: 10.1.0(@types/react@19.2.11)(react@19.1.0) + web-vitals: + specifier: ^5.1.0 + version: 5.1.0 devDependencies: '@eslint/eslintrc': specifier: ^3 @@ -2167,6 +2170,9 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + web-vitals@5.1.0: + resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -4663,6 +4669,8 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 + web-vitals@5.1.0: {} + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 From fba89e1333451f4a4c91a580ddca69592387f71e Mon Sep 17 00:00:00 2001 From: Joao Morais Date: Wed, 4 Feb 2026 14:05:02 -0800 Subject: [PATCH 2/5] change LF to CRLF --- website/app/blog/page.tsx | 248 +++++++++---------- website/app/components/ConditionalNavbar.tsx | 32 +-- website/app/components/PageWrapper.tsx | 20 +- 3 files changed, 150 insertions(+), 150 deletions(-) diff --git a/website/app/blog/page.tsx b/website/app/blog/page.tsx index 0173e1a..3545df9 100644 --- a/website/app/blog/page.tsx +++ b/website/app/blog/page.tsx @@ -1,124 +1,124 @@ -"use client"; -import React from "react"; -import Link from "next/link"; -import postsData from "./posts.json"; - -// Convert posts object to array and sort by date (newest first) -const BLOG_POSTS = Object.values(postsData).sort((a, b) => { - const dateA = new Date(a.date); - const dateB = new Date(b.date); - return dateB.getTime() - dateA.getTime(); -}); - -export default function BlogPage() { - return ( -
-
- - {/* Header */} -
-

- AutoClaw Blog -

-

- Insights on AI agent deployment, OpenClaw, and building the future of - personal AI assistants. -

-
- - {/* Featured Post (First one) */} -
- -
-
- {/* Fallback pattern since we don't have real images yet */} -
-
- -
-
-
-
- - {BLOG_POSTS[0].category} - - {BLOG_POSTS[0].date} - - {BLOG_POSTS[0].readTime} -
-

- {BLOG_POSTS[0].title} -

-

- {BLOG_POSTS[0].excerpt} -

-
- Read Article - - - -
-
-
- -
- - {/* Recent Posts Grid */} -
- {BLOG_POSTS.slice(1).map((post) => ( - -
-
- {/* Visual placeholder */} -
- - {post.title.charAt(0)} - -
-
- -
-
- {post.category} - {post.readTime} -
- -

- {post.title} -

- -

- {post.excerpt} -

- -
- {post.date} - Read more → -
-
- - ))} -
- - {/* Newsletter Signup */} -
-

Subscribe to our newsletter

-

- Get the latest updates on AutoClaw features, OpenClaw tips, and articles about AI agent deployment. -

-
e.preventDefault()}> - - -
-
- -
-
- ); -} +"use client"; +import React from "react"; +import Link from "next/link"; +import postsData from "./posts.json"; + +// Convert posts object to array and sort by date (newest first) +const BLOG_POSTS = Object.values(postsData).sort((a, b) => { + const dateA = new Date(a.date); + const dateB = new Date(b.date); + return dateB.getTime() - dateA.getTime(); +}); + +export default function BlogPage() { + return ( +
+
+ + {/* Header */} +
+

+ AutoClaw Blog +

+

+ Insights on AI agent deployment, OpenClaw, and building the future of + personal AI assistants. +

+
+ + {/* Featured Post (First one) */} +
+ +
+
+ {/* Fallback pattern since we don't have real images yet */} +
+
+ +
+
+
+
+ + {BLOG_POSTS[0].category} + + {BLOG_POSTS[0].date} + + {BLOG_POSTS[0].readTime} +
+

+ {BLOG_POSTS[0].title} +

+

+ {BLOG_POSTS[0].excerpt} +

+
+ Read Article + + + +
+
+
+ +
+ + {/* Recent Posts Grid */} +
+ {BLOG_POSTS.slice(1).map((post) => ( + +
+
+ {/* Visual placeholder */} +
+ + {post.title.charAt(0)} + +
+
+ +
+
+ {post.category} + {post.readTime} +
+ +

+ {post.title} +

+ +

+ {post.excerpt} +

+ +
+ {post.date} + Read more → +
+
+ + ))} +
+ + {/* Newsletter Signup */} +
+

Subscribe to our newsletter

+

+ Get the latest updates on AutoClaw features, OpenClaw tips, and articles about AI agent deployment. +

+
e.preventDefault()}> + + +
+
+ +
+
+ ); +} diff --git a/website/app/components/ConditionalNavbar.tsx b/website/app/components/ConditionalNavbar.tsx index 2cb8cc1..2081511 100644 --- a/website/app/components/ConditionalNavbar.tsx +++ b/website/app/components/ConditionalNavbar.tsx @@ -1,16 +1,16 @@ -"use client"; - -import { usePathname } from "next/navigation"; -import Sidebar from "./Sidebar"; - -export default function ConditionalNavbar() { - const pathname = usePathname(); - const isCallPage = pathname?.startsWith("/call"); - - if (isCallPage) { - return null; - } - - return ; -} - +"use client"; + +import { usePathname } from "next/navigation"; +import Sidebar from "./Sidebar"; + +export default function ConditionalNavbar() { + const pathname = usePathname(); + const isCallPage = pathname?.startsWith("/call"); + + if (isCallPage) { + return null; + } + + return ; +} + diff --git a/website/app/components/PageWrapper.tsx b/website/app/components/PageWrapper.tsx index d3c7996..712ee56 100644 --- a/website/app/components/PageWrapper.tsx +++ b/website/app/components/PageWrapper.tsx @@ -1,10 +1,10 @@ -"use client"; - -export default function PageWrapper({ children }: { children: React.ReactNode }) { - return ( -
- {children} -
- ); -} - +"use client"; + +export default function PageWrapper({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ); +} + From 8bfd546e50d6b09dc452b49b06fa0b00c2be8d07 Mon Sep 17 00:00:00 2001 From: Joao Morais Date: Thu, 5 Feb 2026 06:57:22 -0800 Subject: [PATCH 3/5] move blog content to inside blog --- website/app/blog/[slug]/page.tsx | 2 +- .../blog => app/blog/posts}/curated-skills-philosophy.md | 0 .../{content/blog => app/blog/posts}/self-hosted-vs-cloud.md | 0 .../{content/blog => app/blog/posts}/understanding-api-costs.md | 0 .../blog => app/blog/posts}/why-openclaw-deployment-hard.md | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename website/{content/blog => app/blog/posts}/curated-skills-philosophy.md (100%) rename website/{content/blog => app/blog/posts}/self-hosted-vs-cloud.md (100%) rename website/{content/blog => app/blog/posts}/understanding-api-costs.md (100%) rename website/{content/blog => app/blog/posts}/why-openclaw-deployment-hard.md (100%) diff --git a/website/app/blog/[slug]/page.tsx b/website/app/blog/[slug]/page.tsx index 5be6933..c6d8ec3 100644 --- a/website/app/blog/[slug]/page.tsx +++ b/website/app/blog/[slug]/page.tsx @@ -23,7 +23,7 @@ export function generateStaticParams() { async function getPostContent(slug: string): Promise { try { - const filePath = path.join(process.cwd(), "content", "blog", `${slug}.md`); + const filePath = path.join(process.cwd(), "app", "blog", "posts", `${slug}.md`); const content = await fs.readFile(filePath, "utf-8"); return content; } catch { diff --git a/website/content/blog/curated-skills-philosophy.md b/website/app/blog/posts/curated-skills-philosophy.md similarity index 100% rename from website/content/blog/curated-skills-philosophy.md rename to website/app/blog/posts/curated-skills-philosophy.md diff --git a/website/content/blog/self-hosted-vs-cloud.md b/website/app/blog/posts/self-hosted-vs-cloud.md similarity index 100% rename from website/content/blog/self-hosted-vs-cloud.md rename to website/app/blog/posts/self-hosted-vs-cloud.md diff --git a/website/content/blog/understanding-api-costs.md b/website/app/blog/posts/understanding-api-costs.md similarity index 100% rename from website/content/blog/understanding-api-costs.md rename to website/app/blog/posts/understanding-api-costs.md diff --git a/website/content/blog/why-openclaw-deployment-hard.md b/website/app/blog/posts/why-openclaw-deployment-hard.md similarity index 100% rename from website/content/blog/why-openclaw-deployment-hard.md rename to website/app/blog/posts/why-openclaw-deployment-hard.md From 9b95b4056fe3d1543e7c844b39e2a93a4e5292e7 Mon Sep 17 00:00:00 2001 From: Joao Morais Date: Fri, 6 Feb 2026 19:12:59 -0800 Subject: [PATCH 4/5] bad pricing page --- website/app/pricing/page.tsx | 1003 ++++++++++++++++++++++------------ 1 file changed, 650 insertions(+), 353 deletions(-) diff --git a/website/app/pricing/page.tsx b/website/app/pricing/page.tsx index 69fbd7e..4ada2b1 100644 --- a/website/app/pricing/page.tsx +++ b/website/app/pricing/page.tsx @@ -1,7 +1,8 @@ "use client"; -import React, { useState } from "react"; -// --- Components --- +import React, { useMemo, useState, useEffect, useId } from "react"; + +// --- Small UI primitives --- function CheckIcon({ className = "w-5 h-5" }: { className?: string }) { return ( @@ -11,474 +12,770 @@ function CheckIcon({ className = "w-5 h-5" }: { className?: string }) { ); } +function InfoIcon({ className = "w-4 h-4" }: { className?: string }) { + return ( + + + + ); +} + +function ArrowIcon({ className = "w-5 h-5" }: { className?: string }) { + return ( + + + + ); +} + +function cn(...classes: Array) { + return classes.filter(Boolean).join(" "); +} -// Modern Switch Component -function Switch({ - options, - selected, - onChange -}: { - options: [string, string]; - selected: string; - onChange: (val: string) => void; +function Badge({ + children, + tone = "slate", +}: { + children: React.ReactNode; + tone?: "slate" | "red" | "teal"; }) { + const styles = + tone === "red" + ? "bg-red-500/10 text-red-300 border-red-500/20" + : tone === "teal" + ? "bg-teal-500/10 text-teal-300 border-teal-500/20" + : "bg-slate-500/10 text-slate-300 border-slate-500/20"; + return ( -
- {options.map((option) => ( - - ))} -
+ + {children} + ); } -// Pricing Item Row -function PricingItem({ +// --- Modal with focus/ESC/outside close --- + +function Modal({ + open, + onClose, title, - description, - price, - action, - isOptional = false, + children, }: { + open: boolean; + onClose: () => void; title: string; - description?: string; - price: string; - action: React.ReactNode; - isOptional?: boolean; + children: React.ReactNode; }) { + const titleId = useId(); + + useEffect(() => { + if (!open) return; + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") onClose(); + }; + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, [open, onClose]); + + useEffect(() => { + if (!open) return; + const prev = document.activeElement as HTMLElement | null; + // Basic focus placement + const t = window.setTimeout(() => { + const el = document.querySelector("[data-modal-close]"); + el?.focus?.(); + }, 0); + return () => { + window.clearTimeout(t); + prev?.focus?.(); + }; + }, [open]); + + if (!open) return null; + return ( -
-
-
- {title} - {isOptional && ( - - Optional - - )} +
+
{ + if (e.target === e.currentTarget) onClose(); + }} + aria-hidden="true" + /> +
+
+
+
+

+ {title} +

+

Preview

+
+ +
+
{children}
- {description &&

{description}

}
- -
-
- {action} -
-
- {price} +
+ ); +} + +// --- FAQ Accordion --- + +function FAQItem({ + q, + a, + defaultOpen = false, +}: { + q: string; + a: React.ReactNode; + defaultOpen?: boolean; +}) { + const [open, setOpen] = useState(defaultOpen); + const panelId = useId(); + const buttonId = useId(); + + return ( +
+ + {open && ( +
+ {a}
+ )} +
+ ); +} + +// --- Comparison Table --- + +function ComparisonTable({ + rows, + cols, +}: { + cols: string[]; + rows: Array<{ label: string; values: string[] }>; +}) { + return ( +
+
+
Compare
+ {cols.map((c) => ( +
+ {c} +
+ ))} +
+ +
+ {rows.map((r) => ( +
+
{r.label}
+ {r.values.map((v, i) => ( +
+ {v} +
+ ))} +
+ ))}
); } +// --- Main Page --- + export default function PricingPage() { - // State for toggles - const [hostType, setHostType] = useState<"DIY" | "Assisted">("Assisted"); - const [cloudType, setCloudType] = useState<"Isolated" | "Shared">("Isolated"); - const [aiBrainType, setAiBrainType] = useState<"Fixed" | "Usage">("Fixed"); - const [aiMemType, setAiMemType] = useState<"Fixed" | "Usage">("Usage"); - const [supportEnabled, setSupportEnabled] = useState(true); - const [metricsEnabled, setMetricsEnabled] = useState(true); + const [preview, setPreview] = useState(null); + + const plans = useMemo( + () => [ + { + key: "diy", + badge: { text: "Best for hackers", tone: "slate" as const }, + title: "DIY (Open Source)", + tagline: "Run it yourself.", + price: "$0", + priceNote: "/ forever", + description: + "Use our scripts and docs to deploy OpenClaw yourself. Full control, but you own the setup tax.", + features: [ + "No account required", + "Scripts + battle-tested instructions", + "Bring your own API keys", + "Run locally or on your infra", + "Community support", + "No hosted dashboard", + ], + ctaPrimary: { label: "View Repos", href: "https://github.com/openclaw/openclaw" }, + ctaSecondary: { label: "Read install guide", href: "#" }, + highlight: false, + accent: "slate" as const, + }, + { + key: "selfhost", + badge: { text: "Max privacy", tone: "teal" as const }, + title: "Self-host (Assisted)", + tagline: "You host it; we deploy + keep it running.", + price: "$X", + priceNote: "/ mo", + description: + "Fast deploy to your server via SSH. You bring keys. You get the hosted & maintained dashboard and automatic updates.", + features: [ + "Account required", + "Guided deploy via SSH to your server", + "Battle-tested configs + secure defaults", + "Hosted & maintained web dashboard (paid differentiator)", + "Automatic updates + security patches", + "Curated safe skill updates (skills are an attack surface)", + "Email support + guided fixes", + "BYOK (you manage provider keys)", + ], + ctaPrimary: { label: "Start self-host", href: "/signup" }, + ctaSecondary: { label: "See what we deploy", href: "#" }, + highlight: false, + accent: "teal" as const, + }, + { + key: "managed", + badge: { text: "Most popular", tone: "red" as const }, + title: "Managed (We host)", + tagline: "Fastest path to “it works” — no server, no keys setup.", + price: "$X", + priceNote: "/ mo", + description: + "We host and operate everything end-to-end. Keys included by default. Transparent usage billed at cost.", + features: [ + "Account required", + "We host agent + dashboard + ops", + "Keys included (fastest setup)", + "Usage billed transparently (at cost)", + "Hosted dashboard + updates + monitoring", + "Priority support", + "Memory Graph (coming soon)", + "Prefer BYOK? Optional in onboarding", + ], + ctaPrimary: { label: "Start managed", href: "/signup" }, + ctaSecondary: { label: "Learn about keys", href: "#faq-keys" }, + highlight: true, + accent: "red" as const, + }, + ], + [] + ); + + const compareCols = ["DIY", "Self-host", "Managed"]; + const compareRows = useMemo( + () => [ + { label: "Hosting location", values: ["Yours", "Yours", "Ours"] }, + { label: "Setup time", values: ["Longest", "Minutes", "Fastest"] }, + { label: "Hosted web dashboard", values: ["—", "✓", "✓"] }, + { label: "Updates & maintenance", values: ["Manual", "Automatic", "Fully handled"] }, + { label: "Keys & billing", values: ["BYOK", "BYOK", "Keys included + at-cost usage (BYOK optional)"] }, + { label: "Privacy & control", values: ["You control everything", "Runs on your server", "Hosted container (isolated tenancy)"] }, + { label: "Support", values: ["Community", "Email support", "Priority support"] }, + ], + [] + ); return ( -
+
+
+ {/* Faint section background */} +
-
- {/* Header */} -
+

- Pricing that adapts to you + Pricing that removes the setup tax

-

- Start with our open-source self-hosted version, - or let AutoClaw handle the infrastructure for you. +

+ Get an OpenClaw agent running in minutes — hosted & maintained dashboard, secure defaults, and curated updates.

+
+ hosted & maintained + battle-tested configs + secure defaults +
-
- - {/* LEFT COLUMN: FREE / DIY */} -
-
-
- -
-
- - - + {/* Plans */} +
+
+ {plans.map((p) => ( +
+ {/* subtle overlay */} +
+ {/* top accent */} + {p.highlight && ( +
+ )} + +
+
+ {p.badge.text} + + {/* Inline preview affordances: show only where relevant */} +
+ {(p.key === "selfhost" || p.key === "managed") && ( + + )} + {p.key === "managed" && ( + + )} +
+
+ +

{p.title}

+

{p.tagline}

+ +
+ + {p.price} + + {p.priceNote} +
+ +

{p.description}

-

Self-Hosted

-
- $0 - / forever + +
+ {p.features.map((item) => ( +
+ + {item} +
+ ))}
-

- Full control. You host OpenClaw yourself. The code is open source. -

-
-
- {[ - "OpenClaw open source", - "Self-hosted (Docker/Node)", - "Own your data 100%", - "Bring your own API keys", - "Community support" - ].map((item) => ( -
- - {item} -
- ))} +
+ + {p.ctaPrimary.label} + + + + {p.ctaSecondary.label} + + + {p.key === "managed" && ( +

+ Default: keys included (fastest setup).{" "} + Prefer BYOK? available in onboarding. +

+ )} +
+ ))} +
+
- - View OpenClaw on GitHub - + {/* Comparison */} +
+
+
+

Compare plans

+

Keep it simple: hosting, speed, dashboard, updates, keys, privacy, support.

+ +
- {/* RIGHT COLUMN: MANAGED */} -
-
- {/* Highlight Border */} -
- -
-
-
-

- AutoClaw Managed - - RECOMMENDED - -

-

Modular pricing. Pick exactly what you need.

-
-
-

Starting from

-

$5/mo

-
+ {/* What you get */} +
+
+
+
+
+

Hosted Dashboard

+

+ Access anywhere, no terminal, always current. We host and maintain it so you don’t have to. +

+ +
-
- - {/* Section: Hosting */} -
-

Hosting & Setup

-
- setHostType(v as "DIY" | "Assisted")} - /> - } - /> - setCloudType(v as "Isolated" | "Shared")} - /> - } - /> -
-
- - {/* Section: Intelligence */} -
-

Intelligence (API)

-
- setAiBrainType(v as "Fixed" | "Usage")} - /> - } - /> - setAiMemType(v as "Fixed" | "Usage")} - /> - } - /> - {/* Third party note */} -
- * Third-party APIs (Deepgram, ElevenLabs) billed at cost -
-
-
- - {/* Section: Services */} -
-

Services

-
- setSupportEnabled(!supportEnabled)} - className={`w-12 h-6 rounded-full p-1 transition-colors duration-200 ease-in-out focus:outline-none cursor-pointer ${supportEnabled ? 'bg-red-600' : 'bg-slate-700'}`} - > -
- - } - /> - setMetricsEnabled(!metricsEnabled)} - className={`w-12 h-6 rounded-full p-1 transition-colors duration-200 ease-in-out focus:outline-none cursor-pointer ${metricsEnabled ? 'bg-red-600' : 'bg-slate-700'}`} - > -
- - } - /> -
-
- +
+
+ + Agent health, logs, skills, and configuration in one place +
+
+ + Battle-tested defaults + automatic updates
+
+ + Optional cost visibility and usage breakdowns +
+
+
- {/* CTA Footer */} -
-
-

Ready to deploy your AI assistant?

-

We handle the infrastructure, you focus on what matters.

+
+
+
+
+

Memory Graph

+ Coming soon
- - Deploy Now - - - - +

+ See and control what your agent remembers — transparency and autonomy over long-term context. +

+ +
+
+
+ + Inspect clusters/topics and where they came from +
+
+ + Delete / export / pin memories (user-controlled) +
+
+ + Designed for Managed; optional later for Self-host +
-
- - {/* Billing Principles Section */} -
-
+
+ + {/* FAQ */} +
+
+
+

FAQ

+

Short answers. No surprises.

+
+
+ +
+ + Yes. The code is open. The paid plans include the hosted & maintained{" "} + experience: uptime, updates, secure defaults, and support. + + } + defaultOpen + /> + + You’re paying for hosting and maintenance: an always-on dashboard, upgrades, monitoring, and curated updates without you running infra. + + } + /> + + Managed defaults to keys included (fastest setup). If you prefer, you can bring your own + keys (BYOK) so billing stays with you. + + } + /> + Usage is billed transparently (at cost). We show a clear breakdown by provider and what it cost us.} + /> + + Only what’s needed to provide the service and dashboard. We don’t sell data. Self-host runs on your server; Managed runs in a hosted container + (isolated tenancy). + + } + /> + + Self-host: email support + guided fixes (we may need SSH again if you revoked it). Managed: we fix it as part of ops. + + } + /> +
+
+ + {/* Billing Principles (kept, tightened wording) */} +
+

How we bill

-

- Transparent, fair, and designed to keep you in control. -

+

Transparent, fair, and designed to keep you in control.

- +
{[ { - icon: ( - - - - ), - title: "No API Markup", - description: "We don't resell API keys or add margin on model usage. You pay providers directly at their rates." - }, - { - icon: ( - - - - ), - title: "Itemized Usage", - description: "Monthly receipts show usage by provider—tokens, minutes, calls—plus our subscription fee. No surprises." - }, - { - icon: ( - - - - ), - title: "Subscription Covers", - description: "Web hosting, development, monitoring, alerts, audit logs, and support. All infrastructure costs included." - }, - { - icon: ( - - - - ), - title: "Keys & Data Control", - description: "BYO keys stay in your environment. For Hosted, keys can be yours or ours—rotate anytime." - }, - { - icon: ( - - - - ), - title: "No Content Logging", - description: "We don't store message content in logs by default. Opt in explicitly only if you need debugging." + title: "Usage at cost", + description: "Usage is billed transparently (at cost). Clear breakdowns by provider. No surprises.", }, { - icon: ( - - - - ), - title: "Clear Cancellation", - description: "Cancel any time. No lock-in, no hidden fees, no hoops to jump through." + title: "Itemized receipts", + description: "Monthly receipts show what you used and what it cost — plus the subscription line item.", }, { - icon: ( - - - - ), - title: "Inactivity Nudges", - description: "No usage for a while? We'll email you to downgrade, pause, or cancel—so you don't pay for nothing." + title: "Subscription covers ops", + description: "Hosted dashboard, monitoring, updates, and support. (Self-host includes deploy + updates + dashboard.)", }, { - icon: ( - - - - ), - title: "Always Your Data", - description: "Host anywhere. Export or delete with one click. We can't see or change your message content." + title: "Keys control", + description: "Managed defaults to keys included. Prefer BYOK? Use your own keys and keep billing with you.", }, ].map((item, index) => ( -
-
- {item.icon} -

{item.title}

{item.description}

))}
-
+ - {/* Privacy Section */} -
-
+ {/* Privacy Section (rewrite to avoid over-claims) */} +
+

- Your privacy, by design + Privacy, by design

-

- Different deployment options, same commitment to your privacy. -

+

Different deployment options, same privacy posture: we don’t sell data.

- +
- {/* Private Deploy */} + {/* Self-host / DIY */}
- +
-

Private Deploy

-

Self-hosted or your infrastructure

+

DIY / Self-host

+

Runs on your machine or your server

- We are not able to see, store, or modify message content between you and your assistant. All processing happens in your environment; we only receive aggregate usage metrics. + Your runtime stays in your environment. If you use Self-host (Assisted), you can revoke SSH access at any time.

- + - Maximum privacy guarantee + Max privacy & control
- {/* Hosted */} + {/* Managed */}
- +
-

Hosted

-

Managed by AutoClaw

+

Managed

+

Hosted container (isolated tenancy)

- We don't store or log message content by default. Because we operate the infrastructure, you're trusting us operationally; we provide audit logs and strict access controls. + We operate the infrastructure. We don’t sell data. Access is limited to what’s required to run and support the service.

- + - Audit logs & access controls included + Operational controls + auditability (as implemented)
+
+ + {/* Trust line */} +
+

Powered by OpenClaw · Open source code · Hosted & maintained experience

+
- {/* Trust Indicators */} -
-

- Powered by OpenClaw · Open Source · Your Data, Your Control -

+ {/* Previews */} + setPreview(null)} + title="Hosted Dashboard" + > +
+
+
+ Screenshot placeholder: Overview +
+

Overview

+

One place to see agent health, uptime, skills, and recent activity.

+
+ +
+
+ Screenshot placeholder: Agent detail +
+

Agent detail

+

Logs, configuration, skills, and safe update controls.

+
-
+
+

What you can do

+
    +
  • + + View health and status without running commands +
  • +
  • + + Apply updates safely (security patches, curated skills) +
  • +
  • + + See usage and cost visibility (where enabled) +
  • +
+
+ + + setPreview(null)} + title="Memory Graph (Coming soon)" + > +
+
+
+ Screenshot placeholder: Memory graph view +
+

Inspect + control

+

+ A visual map of what the agent remembers. Designed to make memory transparent and user-controlled. +

+
+
+ +
+

Planned capabilities

+
    +
  • + + View clusters/topics and their sources +
  • +
  • + + Delete/export/pin memories for full autonomy +
  • +
  • + + Clear controls around what’s stored and why +
  • +
+
+
); } From bb822fa9853b2ff9d48a22986c0120bcd6095439 Mon Sep 17 00:00:00 2001 From: Joao Morais Date: Fri, 6 Feb 2026 19:13:42 -0800 Subject: [PATCH 5/5] Revert "bad pricing page" This reverts commit 9b95b4056fe3d1543e7c844b39e2a93a4e5292e7. --- website/app/pricing/page.tsx | 1003 ++++++++++++---------------------- 1 file changed, 353 insertions(+), 650 deletions(-) diff --git a/website/app/pricing/page.tsx b/website/app/pricing/page.tsx index 4ada2b1..69fbd7e 100644 --- a/website/app/pricing/page.tsx +++ b/website/app/pricing/page.tsx @@ -1,8 +1,7 @@ "use client"; +import React, { useState } from "react"; -import React, { useMemo, useState, useEffect, useId } from "react"; - -// --- Small UI primitives --- +// --- Components --- function CheckIcon({ className = "w-5 h-5" }: { className?: string }) { return ( @@ -12,770 +11,474 @@ function CheckIcon({ className = "w-5 h-5" }: { className?: string }) { ); } -function InfoIcon({ className = "w-4 h-4" }: { className?: string }) { - return ( - - - - ); -} - -function ArrowIcon({ className = "w-5 h-5" }: { className?: string }) { - return ( - - - - ); -} - -function cn(...classes: Array) { - return classes.filter(Boolean).join(" "); -} -function Badge({ - children, - tone = "slate", -}: { - children: React.ReactNode; - tone?: "slate" | "red" | "teal"; +// Modern Switch Component +function Switch({ + options, + selected, + onChange +}: { + options: [string, string]; + selected: string; + onChange: (val: string) => void; }) { - const styles = - tone === "red" - ? "bg-red-500/10 text-red-300 border-red-500/20" - : tone === "teal" - ? "bg-teal-500/10 text-teal-300 border-teal-500/20" - : "bg-slate-500/10 text-slate-300 border-slate-500/20"; - return ( - - {children} - +
+ {options.map((option) => ( + + ))} +
); } -// --- Modal with focus/ESC/outside close --- - -function Modal({ - open, - onClose, +// Pricing Item Row +function PricingItem({ title, - children, + description, + price, + action, + isOptional = false, }: { - open: boolean; - onClose: () => void; title: string; - children: React.ReactNode; + description?: string; + price: string; + action: React.ReactNode; + isOptional?: boolean; }) { - const titleId = useId(); - - useEffect(() => { - if (!open) return; - const onKeyDown = (e: KeyboardEvent) => { - if (e.key === "Escape") onClose(); - }; - window.addEventListener("keydown", onKeyDown); - return () => window.removeEventListener("keydown", onKeyDown); - }, [open, onClose]); - - useEffect(() => { - if (!open) return; - const prev = document.activeElement as HTMLElement | null; - // Basic focus placement - const t = window.setTimeout(() => { - const el = document.querySelector("[data-modal-close]"); - el?.focus?.(); - }, 0); - return () => { - window.clearTimeout(t); - prev?.focus?.(); - }; - }, [open]); - - if (!open) return null; - return ( -
-
{ - if (e.target === e.currentTarget) onClose(); - }} - aria-hidden="true" - /> -
-
-
-
-

- {title} -

-

Preview

-
- -
-
{children}
+
+
+
+ {title} + {isOptional && ( + + Optional + + )}
+ {description &&

{description}

}
-
- ); -} - -// --- FAQ Accordion --- - -function FAQItem({ - q, - a, - defaultOpen = false, -}: { - q: string; - a: React.ReactNode; - defaultOpen?: boolean; -}) { - const [open, setOpen] = useState(defaultOpen); - const panelId = useId(); - const buttonId = useId(); - - return ( -
- - {open && ( -
- {a} + +
+
+ {action} +
+
+ {price}
- )} -
- ); -} - -// --- Comparison Table --- - -function ComparisonTable({ - rows, - cols, -}: { - cols: string[]; - rows: Array<{ label: string; values: string[] }>; -}) { - return ( -
-
-
Compare
- {cols.map((c) => ( -
- {c} -
- ))} -
- -
- {rows.map((r) => ( -
-
{r.label}
- {r.values.map((v, i) => ( -
- {v} -
- ))} -
- ))}
); } -// --- Main Page --- - export default function PricingPage() { - const [preview, setPreview] = useState(null); - - const plans = useMemo( - () => [ - { - key: "diy", - badge: { text: "Best for hackers", tone: "slate" as const }, - title: "DIY (Open Source)", - tagline: "Run it yourself.", - price: "$0", - priceNote: "/ forever", - description: - "Use our scripts and docs to deploy OpenClaw yourself. Full control, but you own the setup tax.", - features: [ - "No account required", - "Scripts + battle-tested instructions", - "Bring your own API keys", - "Run locally or on your infra", - "Community support", - "No hosted dashboard", - ], - ctaPrimary: { label: "View Repos", href: "https://github.com/openclaw/openclaw" }, - ctaSecondary: { label: "Read install guide", href: "#" }, - highlight: false, - accent: "slate" as const, - }, - { - key: "selfhost", - badge: { text: "Max privacy", tone: "teal" as const }, - title: "Self-host (Assisted)", - tagline: "You host it; we deploy + keep it running.", - price: "$X", - priceNote: "/ mo", - description: - "Fast deploy to your server via SSH. You bring keys. You get the hosted & maintained dashboard and automatic updates.", - features: [ - "Account required", - "Guided deploy via SSH to your server", - "Battle-tested configs + secure defaults", - "Hosted & maintained web dashboard (paid differentiator)", - "Automatic updates + security patches", - "Curated safe skill updates (skills are an attack surface)", - "Email support + guided fixes", - "BYOK (you manage provider keys)", - ], - ctaPrimary: { label: "Start self-host", href: "/signup" }, - ctaSecondary: { label: "See what we deploy", href: "#" }, - highlight: false, - accent: "teal" as const, - }, - { - key: "managed", - badge: { text: "Most popular", tone: "red" as const }, - title: "Managed (We host)", - tagline: "Fastest path to “it works” — no server, no keys setup.", - price: "$X", - priceNote: "/ mo", - description: - "We host and operate everything end-to-end. Keys included by default. Transparent usage billed at cost.", - features: [ - "Account required", - "We host agent + dashboard + ops", - "Keys included (fastest setup)", - "Usage billed transparently (at cost)", - "Hosted dashboard + updates + monitoring", - "Priority support", - "Memory Graph (coming soon)", - "Prefer BYOK? Optional in onboarding", - ], - ctaPrimary: { label: "Start managed", href: "/signup" }, - ctaSecondary: { label: "Learn about keys", href: "#faq-keys" }, - highlight: true, - accent: "red" as const, - }, - ], - [] - ); - - const compareCols = ["DIY", "Self-host", "Managed"]; - const compareRows = useMemo( - () => [ - { label: "Hosting location", values: ["Yours", "Yours", "Ours"] }, - { label: "Setup time", values: ["Longest", "Minutes", "Fastest"] }, - { label: "Hosted web dashboard", values: ["—", "✓", "✓"] }, - { label: "Updates & maintenance", values: ["Manual", "Automatic", "Fully handled"] }, - { label: "Keys & billing", values: ["BYOK", "BYOK", "Keys included + at-cost usage (BYOK optional)"] }, - { label: "Privacy & control", values: ["You control everything", "Runs on your server", "Hosted container (isolated tenancy)"] }, - { label: "Support", values: ["Community", "Email support", "Priority support"] }, - ], - [] - ); + // State for toggles + const [hostType, setHostType] = useState<"DIY" | "Assisted">("Assisted"); + const [cloudType, setCloudType] = useState<"Isolated" | "Shared">("Isolated"); + const [aiBrainType, setAiBrainType] = useState<"Fixed" | "Usage">("Fixed"); + const [aiMemType, setAiMemType] = useState<"Fixed" | "Usage">("Usage"); + const [supportEnabled, setSupportEnabled] = useState(true); + const [metricsEnabled, setMetricsEnabled] = useState(true); return ( -
-
- {/* Faint section background */} -
+
+
+ {/* Header */} -
+

- Pricing that removes the setup tax + Pricing that adapts to you

-

- Get an OpenClaw agent running in minutes — hosted & maintained dashboard, secure defaults, and curated updates. +

+ Start with our open-source self-hosted version, + or let AutoClaw handle the infrastructure for you.

-
- hosted & maintained - battle-tested configs - secure defaults -
- {/* Plans */} -
-
- {plans.map((p) => ( -
- {/* subtle overlay */} -
- {/* top accent */} - {p.highlight && ( -
- )} - -
-
- {p.badge.text} - - {/* Inline preview affordances: show only where relevant */} -
- {(p.key === "selfhost" || p.key === "managed") && ( - - )} - {p.key === "managed" && ( - - )} -
-
- -

{p.title}

-

{p.tagline}

- -
- - {p.price} - - {p.priceNote} -
- -

{p.description}

+
+ + {/* LEFT COLUMN: FREE / DIY */} +
+
+
+ +
+
+ + +
- -
- {p.features.map((item) => ( -
- - {item} -
- ))} +

Self-Hosted

+
+ $0 + / forever
+

+ Full control. You host OpenClaw yourself. The code is open source. +

+
-
- - {p.ctaPrimary.label} - - - - {p.ctaSecondary.label} - - - {p.key === "managed" && ( -

- Default: keys included (fastest setup).{" "} - Prefer BYOK? available in onboarding. -

- )} -
+
+ {[ + "OpenClaw open source", + "Self-hosted (Docker/Node)", + "Own your data 100%", + "Bring your own API keys", + "Community support" + ].map((item) => ( +
+ + {item} +
+ ))}
- ))} -
-
- {/* Comparison */} -
-
-
-

Compare plans

-

Keep it simple: hosting, speed, dashboard, updates, keys, privacy, support.

+ + View OpenClaw on GitHub +
- -
- {/* What you get */} -
-
-
-
-
-

Hosted Dashboard

-

- Access anywhere, no terminal, always current. We host and maintain it so you don’t have to. -

+ {/* RIGHT COLUMN: MANAGED */} +
+
+ {/* Highlight Border */} +
+ +
+
+
+

+ AutoClaw Managed + + RECOMMENDED + +

+

Modular pricing. Pick exactly what you need.

+
+
+

Starting from

+

$5/mo

+
- -
-
-
- - Agent health, logs, skills, and configuration in one place -
-
- - Battle-tested defaults + automatic updates -
-
- - Optional cost visibility and usage breakdowns +
+ + {/* Section: Hosting */} +
+

Hosting & Setup

+
+ setHostType(v as "DIY" | "Assisted")} + /> + } + /> + setCloudType(v as "Isolated" | "Shared")} + /> + } + /> +
+
+ + {/* Section: Intelligence */} +
+

Intelligence (API)

+
+ setAiBrainType(v as "Fixed" | "Usage")} + /> + } + /> + setAiMemType(v as "Fixed" | "Usage")} + /> + } + /> + {/* Third party note */} +
+ * Third-party APIs (Deepgram, ElevenLabs) billed at cost +
+
+
+ + {/* Section: Services */} +
+

Services

+
+ setSupportEnabled(!supportEnabled)} + className={`w-12 h-6 rounded-full p-1 transition-colors duration-200 ease-in-out focus:outline-none cursor-pointer ${supportEnabled ? 'bg-red-600' : 'bg-slate-700'}`} + > +
+ + } + /> + setMetricsEnabled(!metricsEnabled)} + className={`w-12 h-6 rounded-full p-1 transition-colors duration-200 ease-in-out focus:outline-none cursor-pointer ${metricsEnabled ? 'bg-red-600' : 'bg-slate-700'}`} + > +
+ + } + /> +
+
+
-
-
-
-
-
-
-

Memory Graph

- Coming soon + {/* CTA Footer */} +
+
+

Ready to deploy your AI assistant?

+

We handle the infrastructure, you focus on what matters.

-

- See and control what your agent remembers — transparency and autonomy over long-term context. -

+ + Deploy Now + + + +
- -
-
-
- - Inspect clusters/topics and where they came from -
-
- - Delete / export / pin memories (user-controlled) -
-
- - Designed for Managed; optional later for Self-host -
-
- - {/* FAQ */} -
-
-
-

FAQ

-

Short answers. No surprises.

-
-
- -
- - Yes. The code is open. The paid plans include the hosted & maintained{" "} - experience: uptime, updates, secure defaults, and support. - - } - defaultOpen - /> - - You’re paying for hosting and maintenance: an always-on dashboard, upgrades, monitoring, and curated updates without you running infra. - - } - /> - - Managed defaults to keys included (fastest setup). If you prefer, you can bring your own - keys (BYOK) so billing stays with you. - - } - /> - Usage is billed transparently (at cost). We show a clear breakdown by provider and what it cost us.} - /> - - Only what’s needed to provide the service and dashboard. We don’t sell data. Self-host runs on your server; Managed runs in a hosted container - (isolated tenancy). - - } - /> - - Self-host: email support + guided fixes (we may need SSH again if you revoked it). Managed: we fix it as part of ops. - - } - /> -
-
- - {/* Billing Principles (kept, tightened wording) */} -
-
+
+ + {/* Billing Principles Section */} +
+

How we bill

-

Transparent, fair, and designed to keep you in control.

+

+ Transparent, fair, and designed to keep you in control. +

- +
{[ { - title: "Usage at cost", - description: "Usage is billed transparently (at cost). Clear breakdowns by provider. No surprises.", + icon: ( + + + + ), + title: "No API Markup", + description: "We don't resell API keys or add margin on model usage. You pay providers directly at their rates." + }, + { + icon: ( + + + + ), + title: "Itemized Usage", + description: "Monthly receipts show usage by provider—tokens, minutes, calls—plus our subscription fee. No surprises." + }, + { + icon: ( + + + + ), + title: "Subscription Covers", + description: "Web hosting, development, monitoring, alerts, audit logs, and support. All infrastructure costs included." + }, + { + icon: ( + + + + ), + title: "Keys & Data Control", + description: "BYO keys stay in your environment. For Hosted, keys can be yours or ours—rotate anytime." + }, + { + icon: ( + + + + ), + title: "No Content Logging", + description: "We don't store message content in logs by default. Opt in explicitly only if you need debugging." }, { - title: "Itemized receipts", - description: "Monthly receipts show what you used and what it cost — plus the subscription line item.", + icon: ( + + + + ), + title: "Clear Cancellation", + description: "Cancel any time. No lock-in, no hidden fees, no hoops to jump through." }, { - title: "Subscription covers ops", - description: "Hosted dashboard, monitoring, updates, and support. (Self-host includes deploy + updates + dashboard.)", + icon: ( + + + + ), + title: "Inactivity Nudges", + description: "No usage for a while? We'll email you to downgrade, pause, or cancel—so you don't pay for nothing." }, { - title: "Keys control", - description: "Managed defaults to keys included. Prefer BYOK? Use your own keys and keep billing with you.", + icon: ( + + + + ), + title: "Always Your Data", + description: "Host anywhere. Export or delete with one click. We can't see or change your message content." }, ].map((item, index) => ( -
+
+ {item.icon} +

{item.title}

{item.description}

))}
-
+
- {/* Privacy Section (rewrite to avoid over-claims) */} -
-
+ {/* Privacy Section */} +
+

- Privacy, by design + Your privacy, by design

-

Different deployment options, same privacy posture: we don’t sell data.

+

+ Different deployment options, same commitment to your privacy. +

- +
- {/* Self-host / DIY */} + {/* Private Deploy */}
- +
-

DIY / Self-host

-

Runs on your machine or your server

+

Private Deploy

+

Self-hosted or your infrastructure

- Your runtime stays in your environment. If you use Self-host (Assisted), you can revoke SSH access at any time. + We are not able to see, store, or modify message content between you and your assistant. All processing happens in your environment; we only receive aggregate usage metrics.

- + - Max privacy & control + Maximum privacy guarantee
- {/* Managed */} + {/* Hosted */}
- +
-

Managed

-

Hosted container (isolated tenancy)

+

Hosted

+

Managed by AutoClaw

- We operate the infrastructure. We don’t sell data. Access is limited to what’s required to run and support the service. + We don't store or log message content by default. Because we operate the infrastructure, you're trusting us operationally; we provide audit logs and strict access controls.

- + - Operational controls + auditability (as implemented) + Audit logs & access controls included
-
- - {/* Trust line */} -
-

Powered by OpenClaw · Open source code · Hosted & maintained experience

-
-
- - {/* Previews */} - setPreview(null)} - title="Hosted Dashboard" - > -
-
-
- Screenshot placeholder: Overview -
-

Overview

-

One place to see agent health, uptime, skills, and recent activity.

-
- -
-
- Screenshot placeholder: Agent detail -
-

Agent detail

-

Logs, configuration, skills, and safe update controls.

-
-
- -
-

What you can do

-
    -
  • - - View health and status without running commands -
  • -
  • - - Apply updates safely (security patches, curated skills) -
  • -
  • - - See usage and cost visibility (where enabled) -
  • -
-
- setPreview(null)} - title="Memory Graph (Coming soon)" - > -
-
-
- Screenshot placeholder: Memory graph view -
-

Inspect + control

-

- A visual map of what the agent remembers. Designed to make memory transparent and user-controlled. -

-
+ {/* Trust Indicators */} +
+

+ Powered by OpenClaw · Open Source · Your Data, Your Control +

-
-

Planned capabilities

-
    -
  • - - View clusters/topics and their sources -
  • -
  • - - Delete/export/pin memories for full autonomy -
  • -
  • - - Clear controls around what’s stored and why -
  • -
-
- +
); }