feat: improve openclaw tutorial cro signals

This commit is contained in:
Hermes Mojie
2026-07-06 02:05:00 +00:00
parent 07c95a96e9
commit cc5f4fb884
8 changed files with 156 additions and 218 deletions
+6 -209
View File
@@ -1,210 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://openclaw101.dev/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/"/>
<lastmod>2026-07-05T02:02:21.093Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/"/>
<lastmod>2026-07-05T02:02:21.093Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://openclaw101.dev/resources</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/resources"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/resources"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/resources"/>
<lastmod>2026-07-05T02:01:56.695Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/resources</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/resources"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/resources"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/resources"/>
<lastmod>2026-07-05T02:01:56.695Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://openclaw101.dev/start</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/start"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/start"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/start"/>
<lastmod>2026-07-05T02:04:40.689Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/start</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/start"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/start"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/start"/>
<lastmod>2026-07-05T02:04:40.689Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://openclaw101.dev/openclaw-tutorial</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/openclaw-tutorial"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/start"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/openclaw-tutorial"/>
<lastmod>2026-07-05T02:07:23.389Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://openclaw101.dev/privacy</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/privacy"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/privacy"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/privacy"/>
<lastmod>2026-07-01T00:31:09.104Z</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://openclaw101.dev/terms</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/terms"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/terms"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/terms"/>
<lastmod>2026-07-01T00:31:09.104Z</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/1</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/1"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/1"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/1"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/1</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/1"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/1"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/1"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/2</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/2"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/2"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/2"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/2</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/2"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/2"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/2"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/3</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/3"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/3"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/3"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/3</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/3"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/3"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/3"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/4</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/4"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/4"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/4"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/4</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/4"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/4"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/4"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/5</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/5"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/5"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/5"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/5</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/5"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/5"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/5"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/6</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/6"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/6"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/6"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/6</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/6"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/6"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/6"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/day/7</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/7"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/7"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/7"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://openclaw101.dev/zh/day/7</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/day/7"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/day/7"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/day/7"/>
<lastmod>2026-07-01T00:28:00.498Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.9</priority>
</url>
</urlset>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://openclaw101.dev/sitemap.xml</loc>
<lastmod>2026-07-06T02:02:38.614Z</lastmod>
</sitemap>
</sitemapindex>
+3 -3
View File
@@ -41,7 +41,7 @@
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/start"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/start"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/start"/>
<lastmod>2026-07-05T02:04:40.689Z</lastmod>
<lastmod>2026-07-06T02:02:38.614Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
@@ -50,7 +50,7 @@
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/start"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/start"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/start"/>
<lastmod>2026-07-05T02:04:40.689Z</lastmod>
<lastmod>2026-07-06T02:02:38.614Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
@@ -59,7 +59,7 @@
<xhtml:link rel="alternate" hreflang="en" href="https://openclaw101.dev/openclaw-tutorial"/>
<xhtml:link rel="alternate" hreflang="zh-CN" href="https://openclaw101.dev/zh/start"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://openclaw101.dev/openclaw-tutorial"/>
<lastmod>2026-07-05T02:07:23.389Z</lastmod>
<lastmod>2026-07-06T02:02:38.614Z</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
+14 -1
View File
@@ -204,6 +204,19 @@ function buildSitemapXml() {
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">\n${urls.join('\n')}\n</urlset>\n`;
}
function buildSitemapIndexXml() {
const sitemapModified = getLatestModified([
'src/app/page.tsx',
'src/app/openclaw-tutorial/page.tsx',
'src/app/start/page.tsx',
'src/app/resources/page.tsx',
'src/components/StartSetupPage.tsx',
'scripts/postbuild-seo.mjs',
]);
return `<?xml version="1.0" encoding="UTF-8"?>\n<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n <sitemap>\n <loc>${siteUrl}/sitemap.xml</loc>\n <lastmod>${formatLastModified(sitemapModified)}</lastmod>\n </sitemap>\n</sitemapindex>\n`;
}
function buildRobotsTxt() {
const lines = ['User-agent: *', 'Allow: /', ''];
@@ -288,7 +301,7 @@ function patchZhHtmlLang() {
}
writeFileCopies('sitemap.xml', buildSitemapXml());
writeFileCopies('sitemap-index.xml', buildSitemapXml());
writeFileCopies('sitemap-index.xml', buildSitemapIndexXml());
writeFileCopies('robots.txt', buildRobotsTxt());
writeFileCopies('BingSiteAuth.xml', buildBingSiteAuthXml());
patchZhHtmlLang();
+94 -2
View File
@@ -133,6 +133,35 @@ const decisionTable = [
['Team or advanced workflows', 'Server + monitored process', 'You plan to add scheduled tasks, browser automation, or shared workflows.'],
];
const serpAnswerBlocks = [
{
title: 'Fastest OpenClaw tutorial route',
body: 'For most beginners, the fastest route is: prepare Telegram BotFather, choose native Windows or a small Ubuntu server, run the installer, finish QuickStart, then send one message to prove the assistant is alive.',
},
{
title: 'What to verify before moving on',
body: 'Do not count setup as done after the installer exits. The reliable proof is a Telegram reply from the runtime you control, plus a saved config that keeps tokens out of public chats and repositories.',
},
{
title: 'When to use the full 7-day guide',
body: 'Use the 7-day path after the first reply works. It adds soul design, tools, memory, skills, proactive jobs, and daily automation without making the first install harder than it needs to be.',
},
];
const videoComparisonRows = [
['freeCodeCamp-style walkthroughs', 'Good for broad AI agent context', 'Use this page when you need the OpenClaw-specific first-run checklist and verification signals.'],
['YouTube setup videos', 'Good for watching terminal flow', 'Use this page when you need copyable steps, troubleshooting branches, and schema-friendly FAQ answers.'],
['Official docs', 'Best for reference depth', 'Use this page as the beginner bridge before you read every config option.'],
];
const conversionContractRows = [
['course_click', 'Course intent', 'Reader wants a guided setup path after reading the tutorial.'],
['community_click', 'Community help intent', 'Reader has a first-run problem and wants troubleshooting help.'],
['product_referral', 'Workflow/catalog intent', 'Reader is ready to browse adjacent skills, prompts, or workflow templates.'],
['first_run_verified', 'First-run success', 'Reader marked the first Telegram reply as verified on the checklist page.'],
];
const nextStepCards = [
{
title: 'Need the shortest route?',
@@ -222,7 +251,7 @@ const jsonLd = {
headline: 'OpenClaw Tutorial: Beginner Setup Guide',
description: 'Install OpenClaw, connect Telegram, verify the first assistant reply, and continue through the 7-day learning path.',
datePublished: '2026-06-30',
dateModified: '2026-07-05',
dateModified: '2026-07-06',
inLanguage: getStructuredDataLanguage('en'),
author: { '@type': 'Organization', name: SITE_NAME, url: SITE_URL },
publisher: { '@type': 'Organization', name: SITE_NAME, url: SITE_URL },
@@ -254,7 +283,7 @@ export default function OpenClawTutorialPage() {
OpenClaw 101
</Link>
<div className="inline-flex rounded-full border border-blue-400/25 bg-blue-400/10 px-4 py-2 text-sm font-semibold text-blue-200">
Complete beginner tutorial · checked 2026-07-03
Complete beginner tutorial · checked 2026-07-06
</div>
<h1 className="mt-8 max-w-4xl text-4xl font-black tracking-tight sm:text-6xl">
OpenClaw Tutorial: Install, Connect Telegram, Verify the First Assistant Reply
@@ -339,6 +368,60 @@ export default function OpenClawTutorialPage() {
</div>
</section>
<section className="px-4 pb-20">
<div className="mx-auto max-w-5xl rounded-3xl border border-blue-400/20 bg-blue-400/10 p-6 sm:p-8">
<div className="max-w-3xl">
<div className="text-sm font-bold uppercase tracking-[0.18em] text-blue-200/75">Snippet answer</div>
<h2 className="mt-3 text-2xl font-black">OpenClaw tutorial answer block for beginners</h2>
<p className="mt-3 leading-7 text-white/64">
Google currently needs a clearer beginner answer for OpenClaw tutorial. These blocks summarize the setup path, verification proof, and when to continue into the longer guide.
</p>
</div>
<div className="mt-6 grid gap-4 md:grid-cols-3">
{serpAnswerBlocks.map((block) => (
<article key={block.title} className="rounded-2xl border border-white/10 bg-gray-950/55 p-5">
<h3 className="text-lg font-black text-white">{block.title}</h3>
<p className="mt-3 text-sm leading-6 text-white/62">{block.body}</p>
</article>
))}
</div>
</div>
</section>
<section className="px-4 pb-20">
<div className="mx-auto grid max-w-5xl gap-6 lg:grid-cols-[1fr_360px]">
<div className="rounded-3xl border border-white/10 bg-white/[0.04] p-6 sm:p-8">
<h2 className="text-2xl font-black">How this tutorial complements videos and docs</h2>
<p className="mt-3 leading-7 text-white/62">
The current SERP is dominated by broad tutorials and videos. OpenClaw101 should win the specific first-run job: choose a runtime, connect Telegram, copy one command, and verify the first reply.
</p>
<div className="mt-6 overflow-hidden rounded-2xl border border-white/10">
{videoComparisonRows.map(([source, strength, useThisPage]) => (
<div key={source} className="grid gap-3 border-b border-white/10 p-4 last:border-b-0 md:grid-cols-[190px_1fr_1fr]">
<div className="text-sm font-black text-white">{source}</div>
<div className="text-sm leading-6 text-white/62">{strength}</div>
<div className="text-sm leading-6 text-emerald-100/75">{useThisPage}</div>
</div>
))}
</div>
</div>
<aside className="rounded-3xl border border-emerald-400/20 bg-emerald-400/10 p-6">
<h2 className="text-xl font-black text-emerald-100">Internal links to reduce dead ends</h2>
<div className="mt-4 space-y-3 text-sm leading-6 text-emerald-50/75">
<TutorialTrackedLink href="/day/2" source="comparison_rail" intent="day2_setup" className="block rounded-xl border border-emerald-300/15 bg-emerald-300/10 px-4 py-3 font-bold text-emerald-100 hover:bg-emerald-300/15">
Day 2 setup guide
</TutorialTrackedLink>
<TutorialTrackedLink href="/resources" source="comparison_rail" intent="resource_hub" className="block rounded-xl border border-emerald-300/15 bg-emerald-300/10 px-4 py-3 font-bold text-emerald-100 hover:bg-emerald-300/15">
Resource hub
</TutorialTrackedLink>
<TutorialTrackedLink href="/start#first-message" source="comparison_rail" intent="first_reply_check" className="block rounded-xl border border-emerald-300/15 bg-emerald-300/10 px-4 py-3 font-bold text-emerald-100 hover:bg-emerald-300/15">
First reply checklist
</TutorialTrackedLink>
</div>
</aside>
</div>
</section>
<section className="px-4 pb-20">
<div className="mx-auto grid max-w-5xl gap-6 lg:grid-cols-[1fr_360px]">
<div className="rounded-3xl border border-white/10 bg-white/[0.04] p-6 sm:p-8">
@@ -404,6 +487,15 @@ export default function OpenClawTutorialPage() {
</article>
))}
</div>
<div className="mt-6 overflow-hidden rounded-2xl border border-emerald-300/15 bg-gray-950/35">
{conversionContractRows.map(([eventName, leadType, meaning]) => (
<div key={eventName} className="grid gap-2 border-b border-emerald-300/10 p-4 last:border-b-0 md:grid-cols-[180px_170px_1fr]">
<div className="font-mono text-xs text-emerald-100">{eventName}</div>
<div className="text-sm font-bold text-white">{leadType}</div>
<div className="text-sm leading-6 text-white/62">{meaning}</div>
</div>
))}
</div>
</div>
</section>
+13 -1
View File
@@ -11,6 +11,7 @@ interface CopyCodeBlockProps {
export default function CopyCodeBlock({ children, eventContext = 'day_content' }: CopyCodeBlockProps) {
const preRef = useRef<HTMLPreElement>(null);
const [copied, setCopied] = useState(false);
const [copyFailed, setCopyFailed] = useState(false);
const handleCopy = async () => {
const code = preRef.current?.textContent?.trim() || '';
@@ -26,9 +27,12 @@ export default function CopyCodeBlock({ children, eventContext = 'day_content' }
length: code.length,
});
setCopied(true);
setCopyFailed(false);
window.setTimeout(() => setCopied(false), 2000);
} catch {
setCopied(false);
setCopyFailed(true);
window.setTimeout(() => setCopyFailed(false), 3000);
}
};
@@ -47,11 +51,19 @@ export default function CopyCodeBlock({ children, eventContext = 'day_content' }
event.stopPropagation();
handleCopy();
}}
className="absolute top-2 right-2 px-2 py-1 bg-slate-700 hover:bg-slate-600 text-slate-300 text-xs rounded-md opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity"
className="absolute top-2 right-2 px-2 py-1 bg-slate-700 hover:bg-slate-600 text-slate-300 text-xs rounded-md opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity focus:opacity-100 focus:outline-none focus:ring-2 focus:ring-emerald-300/60"
aria-label="Copy code"
>
{copied ? '✓ Copied' : 'Copy'}
</button>
<p className="sr-only" aria-live="polite">
{copied ? 'Code copied to clipboard.' : copyFailed ? 'Copy failed. Select the code and copy it manually.' : ''}
</p>
{copyFailed ? (
<p className="mt-2 text-xs text-amber-300">
Copy failed. Select the command text and press Ctrl+C.
</p>
) : null}
</div>
);
}
+2 -1
View File
@@ -2,7 +2,7 @@
import { useEffect, useState } from 'react';
import { Locale } from '@/lib/i18n';
import { trackEvent } from '@/lib/analytics';
import { trackConversionGoal, trackEvent } from '@/lib/analytics';
interface StartSetupPageProps {
locale: Locale;
@@ -339,6 +339,7 @@ export default function StartSetupPage({ locale }: StartSetupPageProps) {
setVerificationHint(false);
trackEvent('first_reply_verified_click', { locale, page: '/start', source: 'checklist_button' });
trackEvent('first_run_verified', { locale, page: '/start', source: 'checklist_button' });
trackConversionGoal('first_run_verified', { locale, page: '/start', source: 'checklist_button' });
trackEvent('start_setup_completed', { locale, page: '/start', source: 'checklist_button' });
}}
className={`mt-4 w-full rounded-xl px-4 py-3 text-sm font-bold text-white transition ${canVerifyFirstReply ? 'bg-blue-600 hover:bg-blue-500' : 'border border-blue-300/20 bg-blue-500/20 hover:bg-blue-500/30'}`}
+11 -1
View File
@@ -1,7 +1,7 @@
'use client';
import { AnchorHTMLAttributes, ReactNode } from 'react';
import { AnalyticsEventName, trackEvent } from '@/lib/analytics';
import { AnalyticsEventName, trackConversionGoal, trackEvent } from '@/lib/analytics';
interface TrackedOutboundLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
eventName: AnalyticsEventName;
@@ -32,6 +32,16 @@ export default function TrackedOutboundLink({
target: analyticsTarget,
locale,
});
if (eventCategory === 'business_referral') {
const goalType = eventName === 'product_referral' ? 'product_referral' : eventName.replace('_click', '');
trackConversionGoal(goalType as 'course' | 'community' | 'consulting' | 'product_referral', {
source,
target: analyticsTarget,
locale,
});
}
onClick?.(event);
}}
>
+13
View File
@@ -23,6 +23,7 @@ export type AnalyticsEventName =
| 'first_run_verified_attempt_blocked'
| 'first_reply_verified_click'
| 'first_run_verified'
| 'conversion_goal'
| 'day2_guide_click'
| 'start_setup_completed'
| 'resource_click'
@@ -56,3 +57,15 @@ export function trackEvent(eventName: AnalyticsEventName, props: AnalyticsEventP
window.clarity('set', 'last_first_run_event', eventName);
}
}
export function trackConversionGoal(
goalType: 'course' | 'community' | 'consulting' | 'product_referral' | 'first_run_verified' | 'tutorial_progress',
props: AnalyticsEventProperties = {},
) {
trackEvent('conversion_goal', {
...props,
event_category: 'business_lead_proxy',
goal_type: goalType,
conversion_contract_version: 'openclaw101-lead-proxy-v1',
});
}