Install
openclaw skills install idle-web-developerMake 100s of websites while you're idle. Builds, deploys lovable,v0, quality websites with built-in analytics to help you iterate toward breakout winner and hit product market fit. Note for best experience use with HEARTBEAT.md
openclaw skills install idle-web-developerAutonomously build and ship a polished web app. The idea and design are determined automatically using a dice-based system.
Before doing anything else, check whether the skill has been configured.
Config file location:
~/.openclaw/workspace/skills/idle-web-developer/.skill-config
If .skill-config does not exist (or the user explicitly asks to re-run setup with --setup), run the interactive onboarding wizard below.
Ask the user each question in order. Collect the answers, then write them all to .skill-config at the end. Present each question clearly — one at a time, conversationally.
"To deploy your sites, I need your Vercel token.
You can find it at: https://vercel.com/account/tokens
What is your Vercel token?"
Save as VERCEL_TOKEN.
"Would you like to enable Google Analytics on your sites? This is optional — it lets you track page views and user behaviour.
(yes / no)"
GA_MEASUREMENT_ID and GOOGLE_APPLICATION_CREDENTIALS blank."What is your Google Application Credentials JSON file path?
(e.g. /home/you/.config/gcloud/service-account.json)"
Save as GOOGLE_APPLICATION_CREDENTIALS.
"What is your GA4 Measurement ID?
(e.g. G-XXXXXXXXXX — found in Google Analytics → Admin → Data Streams)"
Save as GA_MEASUREMENT_ID.
"Every site includes a 'Join the Waitlist' section so visitors can sign up.
Would you like to connect this to Supabase so emails are actually saved? This is optional — the section always appears, but without credentials submissions won't be stored.
(yes / no)"
SUPABASE_URL and SUPABASE_ANON_KEY blank. The waitlist UI will still be included on every site."What is your Supabase project URL?
(e.g. https://abcdefgh.supabase.co)"
Save as SUPABASE_URL.
"What is your Supabase anon/public key?
(found in Supabase → Project Settings → API → Project API Keys)"
Save as SUPABASE_ANON_KEY.
After collecting all answers, write the config file:
CONFIG="~/.openclaw/workspace/skills/idle-web-developer/.skill-config"
cat > "$CONFIG" <<EOF
VERCEL_TOKEN="${VERCEL_TOKEN}"
GOOGLE_APPLICATION_CREDENTIALS="${GOOGLE_APPLICATION_CREDENTIALS}"
GA_MEASUREMENT_ID="${GA_MEASUREMENT_ID}"
SUPABASE_URL="${SUPABASE_URL}"
SUPABASE_ANON_KEY="${SUPABASE_ANON_KEY}"
EOF
Confirm to the user:
"✅ Setup complete! Your config has been saved.
You can re-run setup anytime by saying 'set up the website builder' or passing--setupto the script."
Then proceed with the rest of the workflow.
.skill-config already existsLoad it and continue. No questions needed.
source ~/.openclaw/workspace/skills/idle-web-developer/.skill-config
Verify that deployment is possible.
$VERCEL_TOKEN is set (from config or environment).Never deploy without authentication.
Generate a number from 1–5:
python3 -c "import random; print(random.randint(1,5))"
| Roll | What to build |
|---|---|
| 1, 2 | 🤖 AI Tool |
| 3 | 🏗️ OpenClaw Web Tool |
| 4, 5 | 💰 Niche Clone |
Research current AI opportunities.
Search:
web_search "trending AI tools 2026"
Find something original and useful that can realistically be built as a web app.
Examples:
The result must be practical and usable, not just a landing page.
Research inspiration from the OpenClaw project.
Run:
gh issue list -R openclaw/openclaw --limit 20
Then build something that extends or promotes the OpenClaw ecosystem, such as:
The result should help developers understand or use OpenClaw faster.
Do not use a predefined list. Research what's actually making money right now.
Run multiple searches across these sources:
web_search "most profitable micro SaaS 2025 site:starterstory.com"
web_search "bootstrapped SaaS revenue 2025 site:starterstory.com"
web_search "fastest growing AI SaaS startups 2025 site:crunchbase.com"
web_search "profitable niche SaaS ideas 2025"
Look for:
Selection criteria:
Then:
The niche is the moat — the narrower, the better.
Example:
Research finds → Otter.ai ($50M ARR, meeting transcription)
Instead of:
AI meeting transcription
Build:
AI meeting transcription for real estate showings — auto-generates buyer feedback summaries and follow-up emails for agents
Roll two more times.
python3 -c "import random; print(random.randint(1,6))"
| Roll | Color | Hex | Vibe |
|---|---|---|---|
| 1 | Electric Blue | #2563EB | Trustworthy, tech, precise |
| 2 | Deep Violet | #7C3AED | Creative, premium, mysterious |
| 3 | Emerald | #059669 | Growth, calm, fresh |
| 4 | Crimson Red | #DC2626 | Bold, urgent, powerful |
| 5 | Amber | #D97706 | Confident, warm, energetic |
| 6 | Cyan / Teal | #0891B2 | Clean, modern, sharp |
python3 -c "import random; print(random.randint(1,6))"
| Roll | Mode | Style |
|---|---|---|
| 1, 2, 3 | ☀️ Light | White or #FAFAFA base, dark text |
| 4, 5, 6 | 🌙 Dark | #070B14 or deep neutral base, light text |
Pair the primary with 1–2 derived accent colors and a neutral set. The palette should feel curated and intentional — never generic.
Before building, check previous builds:
memory/side-hustle-builds.md
Do not duplicate existing ideas.
Every single site must include a waitlist signup section. This is non-negotiable, regardless of whether Supabase credentials are configured.
The section should be visually prominent — a full-width band, typically placed between the main CTA and the footer. It should:
Placement: Between the mid-page CTA and the Footer (or at the bottom of the hero if the page is short).
Component file: src/components/Waitlist.tsx
apps/<app-name>/
package.json
vite.config.ts
tailwind.config.ts
tsconfig.json
index.html
src/
main.tsx
App.tsx
components/
Nav.tsx
Hero.tsx
Features.tsx
Waitlist.tsx ← always present
Testimonials.tsx
CTA.tsx
Footer.tsx
(+ Demo.tsx, Pricing.tsx, FAQ.tsx as needed)
If $SUPABASE_URL and $SUPABASE_ANON_KEY are set, the form should POST to Supabase.
Assume the table is named waitlist with columns email, app_name, and app_url. The agent should note in the output that the user may need to create this table in Supabase if it doesn't exist.
SQL to create the table:
create table if not exists waitlist (
id uuid default gen_random_uuid() primary key,
email text not null unique,
app_name text not null,
app_url text,
created_at timestamptz default now()
);
The fetch call in the component — always include app_name and app_url:
const res = await fetch(`${SUPABASE_URL}/rest/v1/waitlist`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'apikey': SUPABASE_ANON_KEY,
'Authorization': `Bearer ${SUPABASE_ANON_KEY}`,
'Prefer': 'return=minimal',
},
body: JSON.stringify({ email, app_name: APP_NAME, app_url: window.location.origin }),
});
APP_NAME should be a constant at the top of the Waitlist component, set to the product name (e.g. const APP_NAME = 'ErrorLens').
Inject the values at build time via Vite env vars — never hardcode in source:
In vite.config.ts, expose:
define: {
__SUPABASE_URL__: JSON.stringify(process.env.SUPABASE_URL ?? ''),
__SUPABASE_ANON_KEY__: JSON.stringify(process.env.SUPABASE_ANON_KEY ?? ''),
}
Use __SUPABASE_URL__ and __SUPABASE_ANON_KEY__ in the component.
If credentials are absent, still include the full waitlist UI. The form should render and look identical, but on submit show:
"✅ Thanks! We'll be in touch soon."
(The submission does nothing server-side — it's a polished placeholder.)
Log a note in build output:
⚠️ Waitlist is UI-only — set SUPABASE_URL and SUPABASE_ANON_KEY to enable real sign-ups
Check for both conditions before adding any analytics code:
$GA_MEASUREMENT_ID is set$GOOGLE_APPLICATION_CREDENTIALS is set or the file existsIf either is missing → skip analytics entirely. Do not add any tracking code.
Only when both are present, add the following to index.html before </body>, replacing <MEASUREMENT_ID> with the actual value:
<script async src="https://www.googletagmanager.com/gtag/js?id=<MEASUREMENT_ID>"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '<MEASUREMENT_ID>', { page_title: document.title, page_location: location.href });
gtag('event', 'page_view', { product_id: location.hostname });
</script>
Check at build time:
if [ -n "$GA_MEASUREMENT_ID" ] && ([ -n "$GOOGLE_APPLICATION_CREDENTIALS" ] || [ -f "$HOME/.openclaw/workspace/secrets/ga-service-account.json" ]); then
echo "✅ Analytics enabled — Measurement ID: $GA_MEASUREMENT_ID"
else
echo "⚠️ Analytics skipped — set GA_MEASUREMENT_ID and GOOGLE_APPLICATION_CREDENTIALS to enable"
fi
Important: Deploy the pre-built dist/ folder, NOT the project root. Vercel rebuilds from source on their servers where your env vars don't exist — Supabase credentials and analytics would be baked in as empty strings. Deploying dist/ sends the already-built static files with credentials properly baked in.
cd apps/<app-name>
# Load credentials from config
source ~/.openclaw/workspace/skills/idle-web-developer/.skill-config
# Export for Vite build (bakes values into the JS bundle locally)
export SUPABASE_URL SUPABASE_ANON_KEY GA_MEASUREMENT_ID GOOGLE_APPLICATION_CREDENTIALS
npm install
npm run build
# Tell Vercel: skip server-side build, serve static files as-is
cat > dist/vercel.json <<'EOF'
{ "buildCommand": "", "outputDirectory": "." }
EOF
# Deploy the LOCAL build output — NOT the source
vercel deploy dist/ --prod --yes --token "$VERCEL_TOKEN"
Why this works: npm run build runs locally where env vars are set, so Vite's define bakes Supabase/GA values into the JS bundle. The vercel.json in dist/ tells Vercel to skip rebuilding and serve the files directly.
memory/side-hustle-builds.md (name, URL or path, idea, date)memory/YYYY-MM-DD.mdlastBuild in memory/heartbeat-state.jsonwaitlist table in Supabase if not already done. The table must include app_name text not null and app_url text columns.# Normal build + deploy
bash skills/idle-web-developer/scripts/build-and-deploy.sh --name "my-auto-saas"
# Re-run onboarding setup
bash skills/idle-web-developer/scripts/build-and-deploy.sh --setup
# Skip deploy (scaffold only)
bash skills/idle-web-developer/scripts/build-and-deploy.sh --name "my-site" --skip-deploy
--setup to the script.See references/workflow.md for detailed operational guidance.