We run the LLM. You send a prompt, you get text back. Free tier gives you 200 requests/day — enough to prototype and ship. Drop-in Python, works with any Ren'Py project.
You want NPCs that actually respond to the player instead of cycling through canned lines. You've looked at Ollama, llama.cpp, KoboldCpp. They work — until your players need a 3090 to run your visual novel.
This API lets you offload the LLM to us. Your game sends a prompt, gets a response. The player just needs a browser to log in once. After that, it's HTTP calls from your Ren'Py script.
You can. And if you have the time to build your own account system, token management, rate limiting, and billing dashboard — go for it. Seriously. But if you'd rather spend that time on your actual game, read on.
The core problem with shipping your own API key inside a Ren'Py game: it's a zip of Python files. Anyone can open it and extract your key in 30 seconds. Even if you obfuscate it — your game gets 500 downloads, that's 500 people burning through your credits. A popular game with active players can rack up hundreds of dollars in API costs in a week. That bill goes to you.
With this API, the player authenticates with their own free account. You ship zero API keys. You pay nothing. Each player gets their own rate limit. Your game scales to 10,000 players and your cost is still $0.
| Your own key | This API | |
|---|---|---|
| API key in game files | Yes — extractable | None |
| Who pays per request | You, the dev | Nobody (free tier) |
| 1,000 players × 100 req/day | ~$15–50/day on your card | $0 to you |
| Key gets leaked | Your bill explodes | N/A — no key to leak |
| Rate limiting | Build it yourself | Built in, per player |
| Auth & accounts | Build it yourself | Google login, handled |
Could you build all of this yourself? Absolutely. But that's weeks of backend work that has nothing to do with making your game better. This exists so you can skip that part and focus on what matters — your characters, your story, your game design.
Three steps. No SDK, no library to install. Just requests (comes with Ren'Py) and a few lines of Python.
localhost with a JWT. Done once.Opens in browser. Player logs in with Google. Redirects back to your localhost callback with ?token=JWT&email=user@email.com.
Send a prompt, get generated text. Auth via Authorization: Bearer {JWT}. Returns {"response": "..."}.
Returns {"status": "ok"} if the JWT is valid. 401 if expired. Use it on game launch.
Copy-paste into your Ren'Py project. Adjust the prompt building to your game's characters.
Start a tiny HTTP server on localhost, open the browser, wait for the redirect with the token.
init python:
import requests
import webbrowser
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
KRAKEN_URL = "https://smut.fr"
AUTH_PORT = 52431
# persistent token — survives game restarts
if persistent.kraken_token is None:
persistent.kraken_token = None
if persistent.kraken_email is None:
persistent.kraken_email = None
class _AuthHandler(BaseHTTPRequestHandler):
"""Catches the redirect from the website."""
token = None
email = None
error = None
def do_GET(self):
params = parse_qs(urlparse(self.path).query)
if "token" in params:
_AuthHandler.token = params["token"][0]
_AuthHandler.email = params.get("email", [""])[0]
body = b"<h2>Logged in! You can close this tab.</h2>"
else:
_AuthHandler.error = params.get("error", ["Unknown error"])[0]
body = b"<h2>Login failed. Check the game.</h2>"
self.send_response(200)
self.send_header("Content-Type", "text/html")
self.end_headers()
self.wfile.write(body)
def log_message(self, *args):
pass # silence console noise
def kraken_login():
"""Opens browser, waits for token, stores it."""
_AuthHandler.token = None
_AuthHandler.error = None
srv = HTTPServer(("127.0.0.1", AUTH_PORT), _AuthHandler)
srv.timeout = 120 # 2 min max wait
webbrowser.open(
"{}/game-auth?callback=http://localhost:{}".format(KRAKEN_URL, AUTH_PORT)
)
srv.handle_request() # blocks until redirect arrives
srv.server_close()
if _AuthHandler.token:
persistent.kraken_token = _AuthHandler.token
persistent.kraken_email = _AuthHandler.email
return True
return False
def kraken_generate(prompt, temperature=0.7, max_tokens=80):
"""Send a prompt, get text back. Returns None on error."""
if not persistent.kraken_token:
return None
try:
r = requests.post(
"{}/api/game/generate".format(KRAKEN_URL),
json={
"prompt": prompt,
"temperature": temperature,
"max_tokens": max_tokens,
},
headers={
"Authorization": "Bearer " + persistent.kraken_token,
"Content-Type": "application/json",
},
timeout=15,
)
if r.status_code == 200:
return r.json().get("response", "")
if r.status_code == 401:
persistent.kraken_token = None # token expired
return None
except Exception:
return None
def kraken_health():
"""Returns True if the token is still valid."""
if not persistent.kraken_token:
return False
try:
r = requests.get(
"{}/api/game/health".format(KRAKEN_URL),
headers={"Authorization": "Bearer " + persistent.kraken_token},
timeout=5,
)
return r.status_code == 200
except Exception:
return False
label tavern:
scene bg tavern
show eileen happy
# build your prompt however you want
$ prompt = """You are Eileen, a sharp-tongued tavern owner.
You're tired, it's late, and the player just walked in.
Respond in 1-2 sentences. Stay in character.
Player: Got any rooms?
Eileen:"""
$ reply = kraken_generate(prompt, temperature=0.8, max_tokens=60)
if reply:
e "[reply]"
else:
# fallback — hardcoded line if API is down
e "We're full. Try the inn down the road."
{
"prompt": "You are Eileen, a tavern owner.\n\nPlayer: Got any rooms?\n\nEileen:",
"temperature": 0.7,
"max_tokens": 80
}
{
"response": "We're full tonight. But if you can handle a cot by the fireplace, that'll be two silver."
}
// 401 — token expired or invalid
{"error": "Invalid or expired token"}
// 429 — hit the daily limit
{"error": "Rate limit exceeded. Try again later."}
// 400 — no prompt provided
{"error": "Missing required field: prompt"}
temperature (0.0–1.0, default 0.7) and max_tokens (1–500, default 80) are optional. Prompt is required.
Per-user, per-day. The limits apply to the player's account, not your game — so if 100 players use your game, each gets their own quota.
| Tier | Requests / day | Notes |
|---|---|---|
| Free | 200 | Enough for a few hours of gameplay |
| Premium | 2,000 | For heavier usage or longer sessions |
When a player hits the limit, the API returns 429. Handle it with a fallback line in your script — the player won't notice.
The pattern is always the same: build a prompt, call the API, use the response as dialogue text. How you build the prompt is where your game design lives.
We route through our own API keys. Currently using fast models optimized for short-form dialogue. You don't need to know or care — you send text, you get text. If we switch providers, your game doesn't break.
Yes. They sign up with Google (one click) the first time. After that, the JWT lasts 30 days. They won't see the login again for a month.
The prompt is yours. We don't filter input or output. Use responsibly.
Always have a fallback. A hardcoded line, a random pick from a list — anything. Your game should never soft-lock because an HTTP call failed. Wrap the call in a try/except like the code above does.
Yes. It's a standard REST API. Unity (C# HttpClient), Godot (HTTPRequest), RPG Maker (via plugins), raw Python, whatever. The endpoints don't care what's calling them.
Not required, but appreciated. A small credit in your game's settings or about screen helps other devs discover the API. Once our affiliation program launches, a visible mention will be how we track attribution for revenue sharing — so it'll be in your interest to include it.
We're planning an affiliation program: games that bring players to the platform will earn a percentage of any premium subscriptions those players buy. Our store page isn't live yet, so this isn't active — but it's on the roadmap. We're telling you now so you know the direction.
Copy the integration code above, drop it in your Ren'Py project, and you're done. No API key to manage, no account to create on your side. Your players handle their own login — you just write the game.