vilow.dev · Integrations · v0 (Vercel)
Add Vilow to a v0 app
v0 generates Next.js + React. Use a Server Action (or a Route Handler) to keep the Vilow API key on the server and return only the reply to the browser. Deploys to Vercel; their env-var system is the natural place for the key.
-
Get a Vilow API key
vilow.dev/dashboard → API keys → Create. Copy the
ck_live_…string. -
Save the key in Vercel project settings
In your Vercel dashboard for this project: Settings → Environment Variables → Add:
VILOW_API_KEY = ck_live_... VILOW_API_BASE = https://api.vilow.dev/v1
Apply to Production + Preview (so v0's preview deploys get the key too) + Development (for
vercel dev). -
Add a Server Action
Ask v0: "Add a Server Action
chatWithVilowinapp/actions.tsthat POSTs tohttps://api.vilow.dev/v1/chat/{user}/{character}/sendwith theVILOW_API_KEYenvironment variable."If you'd rather paste:
// app/actions.ts "use server"; const KEY = process.env.VILOW_API_KEY!; const API = process.env.VILOW_API_BASE ?? "https://api.vilow.dev/v1"; export async function chatWithVilow(opts: { user_id: string; character_id?: number | null; message: string; }) { let cid = opts.character_id; if (!cid) { await fetch(`${API}/users`, { method: "POST", headers: { "X-API-Key": KEY, "Content-Type": "application/json" }, body: JSON.stringify({ external_id: opts.user_id, display_name: "v0 visitor" }), }); const r = await fetch(`${API}/users/${opts.user_id}/characters`, { method: "POST", headers: { "X-API-Key": KEY, "Content-Type": "application/json" }, body: JSON.stringify({ name: "Aria", default_language: "auto" }), }); cid = (await r.json()).id; } const chat = await fetch(`${API}/chat/${opts.user_id}/${cid}/send`, { method: "POST", headers: { "X-API-Key": KEY, "Content-Type": "application/json" }, body: JSON.stringify({ message: opts.message }), cache: "no-store", }); const data = await chat.json(); return { ...data, character_id: cid }; }
-
Use the action from a Client Component
"use client"; import { chatWithVilow } from "./actions"; import { useState, useMemo } from "react"; export default function Chat() { const [text, setText] = useState(""); const [reply, setReply] = useState(""); const [cid, setCid] = useState<number | null>(null); const uid = useMemo(() => { const k = "vilow_uid"; let u = typeof window !== "undefined" ? localStorage.getItem(k) : null; if (!u) { u = "u_" + crypto.randomUUID(); localStorage.setItem(k, u); } return u; }, []); async function send() { const r = await chatWithVilow({ user_id: uid, character_id: cid, message: text }); if (r.character_id) setCid(r.character_id); setReply(r.reply); setText(""); } return ( <div> <input value={text} onChange={(e) => setText(e.target.value)} /> <button onClick={send}>Send</button> <p>{reply}</p> </div> ); }
-
Test on the v0 preview URL
v0's previews live on
v0.devand Vercel's*.vercel.app. Both are CORS-allowed by Vilow out of the box (the request actually goes server-side anyway). Send a message — you should get a stateful reply that remembers across page reloads thanks to localStoragevilow_uid+character_id. -
Push to production
Click Deploy in v0 → Vercel will build with the env vars you set. Custom domain in Vercel Settings → Domains.
Common gotchas
- "VILOW_API_KEY is undefined" in dev — Vercel pulls env into
.env.localonly if you runvercel env pullfirst. Or run viavercel devinstead ofnext dev. - Server Actions return slow on cold start — Vercel's free tier has cold starts. Show a loading state. After the first call, subsequent turns are fast.
- "Cannot find module 'next'" if v0 generated something other than Next.js — the same logic works as a Route Handler at
app/api/.../route.ts.