vilow.dev · Integrations · Lovable

Add Vilow to a Lovable app

Lovable generates React/Next.js apps from prompts. To give your app a stateful AI companion (memory + emotions + relationships), call Vilow's REST API. We'll use Lovable's recommended Supabase backend to keep the API key server-side — exposing it in client code would let any visitor spend your credits.

  1. Get a Vilow API key

    Open vilow.dev/dashboard → sign in with email (magic link) → tab API keys → click Create key. You'll get something that starts with ck_live_. Copy it once — you won't see it again.

  2. Connect Supabase to your Lovable project

    In Lovable: Settings → Integrations → Supabase → Connect. Lovable will create (or attach) a Supabase project and start using it for auth, database, and Edge Functions. This is where our API key will live.

    Already using a different backend? Skip Supabase and adapt step 3 to your platform's secret-store + serverless-function equivalent — the principle is identical.

  3. Store the Vilow API key as a Supabase secret

    In Supabase Dashboard: Edge Functions → Secrets → Add new. Name it VILOW_API_KEY, paste the ck_live_… value.

    Why not just put it in Lovable's environment? Lovable env vars are baked into the client bundle and visible in DevTools. Supabase Edge Function secrets are server-only — that's where the key belongs.
  4. Create an Edge Function as a thin proxy

    Ask Lovable: "Add a Supabase Edge Function called vilow-chat that proxies POST requests to https://api.vilow.dev/v1/chat/{user}/{character}/send using the VILOW_API_KEY secret."

    If you'd rather paste it yourself, Lovable will accept this:

    // supabase/functions/vilow-chat/index.ts
    import { serve } from "https://deno.land/std/http/server.ts";
    
    const VILOW_KEY = Deno.env.get("VILOW_API_KEY")!;
    const VILOW_API = "https://api.vilow.dev/v1";
    
    serve(async (req) => {
      if (req.method !== "POST") return new Response("POST only", { status: 405 });
      const { user_id, character_id, message, persona } = await req.json();
    
      // Lazy-create the character on first turn (no character_id yet).
      let cid = character_id;
      if (!cid) {
        await fetch(`${VILOW_API}/users`, {
          method: "POST",
          headers: { "X-API-Key": VILOW_KEY, "Content-Type": "application/json" },
          body: JSON.stringify({ external_id: user_id, display_name: "Lovable visitor" }),
        });
        const r = await fetch(`${VILOW_API}/users/${user_id}/characters`, {
          method: "POST",
          headers: { "X-API-Key": VILOW_KEY, "Content-Type": "application/json" },
          body: JSON.stringify(persona ?? { name: "Aria", gender: "female", default_language: "auto" }),
        });
        cid = (await r.json()).id;
      }
    
      const chat = await fetch(`${VILOW_API}/chat/${user_id}/${cid}/send`, {
        method: "POST",
        headers: { "X-API-Key": VILOW_KEY, "Content-Type": "application/json" },
        body: JSON.stringify({ message }),
      });
      const data = await chat.json();
    
      return new Response(JSON.stringify({ ...data, character_id: cid }), {
        headers: { "Content-Type": "application/json" },
      });
    });
  5. Call the Edge Function from your Lovable React

    Drop a chat input + send handler into your component:

    // In any Lovable-generated React component
    const [characterId, setCharacterId] = useState(
      () => localStorage.getItem("vilow_cid"),
    );
    const userId = useMemo(() => {
      let u = localStorage.getItem("vilow_uid");
      if (!u) {
        u = "u_" + crypto.randomUUID();
        localStorage.setItem("vilow_uid", u);
      }
      return u;
    }, []);
    
    async function send(text) {
      const r = await supabase.functions.invoke("vilow-chat", {
        body: { user_id: userId, character_id: characterId, message: text },
      });
      if (r.data?.character_id && r.data.character_id !== characterId) {
        setCharacterId(r.data.character_id);
        localStorage.setItem("vilow_cid", r.data.character_id);
      }
      return r.data?.reply;
    }
  6. Test from Lovable's preview

    Lovable's hot-reload preview runs on a *.lovable.app URL. Our API already allows that origin via CORS, so the Edge-Function call works from the live preview without extra setup. Send a message — you should see the character reply with growing memory across turns.

    Sanity-check via curl from your terminal too:

    curl -X POST https://api.vilow.dev/v1/chat/u_test/CID/send \
      -H "X-API-Key: ck_live_..." \
      -H "Content-Type: application/json" \
      -d '{"message":"Hi, what was the last thing we talked about?"}'
  7. Ship it

    Lovable deploys to {slug}.lovable.app automatically. Custom domains: Settings → Domains → Add. Edge Function secrets and CORS continue to work on custom domains.

Common gotchas

What you got

Your Lovable app now has an AI companion that remembers conversations across sessions, develops emotions and a relationship with each visitor, and sounds increasingly like a person, not a chatbot. To go further: voice replies, intimate-mode (consent-gated), Snapshot Import (clone someone from a description) — all opt-in via the same API. See the main docs.