Tsukutta
AI/Search with AI
AI/Search with AIGuide
Log inShare appShare
Tsukutta
Log inGuideFree Browser GamesStats & dataIdea BoardFor developersWhat's newContact UsSurveyTerms of ServicePrivacy PolicyCommercial transactions disclosure
© 2026 Tsukutta.
HomeSearchArticlesDevsSaved

Developer documentation

Tsukutta SDK Integration Guide

This page summarizes the minimal steps to add Tsukutta login, cloud save, and leaderboards to external apps.

Quick start

  1. In My Page, open "Manage / SDK" under your app's card, turn on "SDK integration", and copy the app ID shown.
  2. Paste the code below into your HTML and replace YOUR_APP_ID with the ID you copied.
  3. Done. The button appears automatically and signs users in on click.
<script src="https://tsukutta.app/sdk/v1.js" data-app-id="YOUR_APP_ID"></script>
<div data-tsukutta-login></div>

This is how it looks

Enable SDK integration in My Page →

Live sample: Cloud Notes

Sign in, write a note, and it is saved to your Tsukutta account — reopen it on another device or browser and it is still there. Built with just Sign in with Tsukutta and cloud storage; no server or database of your own. Try it first.

Open the live demo →

The HTML of this demo page is the full, copy-paste source (use your browser's View Source to copy it). Change data-app-id to your own app ID to make it yours.

Let your AI implement it

No coding. Just paste the one line below into your AI (Cursor / Claude / v0, etc.).

Read https://tsukutta.app/sdk/llms.txt and add a "Sign in with Tsukutta" button to my app. The app-id is "YOUR_APP_ID".

Even when you need server-side verification (accounts, payments), the prompt above is enough for the AI to implement it correctly. The details below are for people wiring it up by hand.

Customize the button▼
  • data-theme="dark" — dark button on brand green (default is light)
  • data-label="Continue with" — replace the default label text
  • data-redirect="/home" — navigate to a URL after a successful login
Rendering from code (React, etc.)▼

For apps that render dynamically, call it in one line targeting an element. The return value cleans up (unsubscribe + remove the button).

const cleanup = Tsukutta.renderLoginButton("#login", {
  theme: "light",            // "light" | "dark"
  label: "Sign in with",     // optional label text
  redirect: "/home",         // navigate after a successful login (optional)
  onLogin: (user) => setUser(user),
});
Get the signed-in user▼

Handle the sign-in state on the client like this:

// Current user (null when signed out)
const user = Tsukutta.user;   // { id, name, avatarUrl }

// React to sign-in / sign-out
Tsukutta.onAuthChange((user) => { updateUI(user); });

// Sign out
Tsukutta.logout();
Verify on your server (only for accounts / payments)▼

To link "Login with Tsukutta" to your own account system, send the token obtained in the browser to your own server, then verify it against the verification endpoint. Never trust data coming from the browser as-is; always verify on your server.

  1. Client: after Tsukutta.login() completes, send Tsukutta.token to your own server
  2. Your server: call POST https://tsukutta.app/api/sdk/v1/verify with Authorization: Bearer <token>
  3. Your server: link the userId from the response to your own account system
// 1) Browser: send the SDK token to your own server
const user = await Tsukutta.login();
await fetch("/api/auth/tsukutta", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ token: Tsukutta.token }),
});

// 2) Your server: verify the token with Tsukutta
const res = await fetch("https://tsukutta.app/api/sdk/v1/verify", {
  method: "POST",
  headers: { Authorization: "Bearer " + token },
});
if (!res.ok) throw new Error("verify failed");
const data = await res.json();

// 3) CRITICAL: check the token audience
if (data.appId !== MY_APP_ID) throw new Error("audience mismatch");

// 4) Link data.userId to your own account system

Critical: check appId (audience)

Always confirm that the appId in the verify response matches your own app ID. Tokens are issued per app, so if you skip this check, a malicious app could replay a token it legitimately obtained for itself and impersonate your users in your app.

Single-file HTML sample▼

Flow example:

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Tsukutta SDK sample</title>
    <script src="https://tsukutta.app/sdk/v1.js" data-app-id="YOUR_APP_ID"></script>
  </head>
  <body>
    <button id="login-button">Login with Tsukutta</button>
    <button id="save-button">Save progress</button>
    <button id="score-button">Submit score</button>
    <pre id="log"></pre>

    <script>
      const log = (message) => {
        const target = document.getElementById("log");
        if (target) target.textContent += message + "\n";
      };

      document.getElementById("login-button")?.addEventListener("click", async () => {
        try {
          const user = await Tsukutta.login();
          log("login: " + user.id);
        } catch (error) {
          log("login error: " + error);
        }
      });

      document.getElementById("save-button")?.addEventListener("click", async () => {
        try {
          await Tsukutta.storage.set("progress/level", { level: 3 });
          log("storage.set: ok");
        } catch (error) {
          log("storage.set error: " + error);
        }
      });

      document.getElementById("score-button")?.addEventListener("click", async () => {
        try {
          const best = await Tsukutta.scores.submit("global", 1200, { stage: 3 });
          log("scores.submit: " + best);
        } catch (error) {
          log("scores.submit error: " + error);
        }
      });

      (async () => {
        const top = await Tsukutta.scores.top("global", { limit: 5 });
        const views = await Tsukutta.counters.get("visits");
        log("scores.top top[0]: " + JSON.stringify(top[0] ?? null));
        log("counters.get: " + views);
      })();
    </script>
  </body>
</html>
Public read APIs (no login required)▼

scores.top and counters.get can be called without login. Both require app_id query parameter.

  • scores.top: fetch public leaderboard entries for a board, for example scores.top("global", { limit: 5 }).
  • counters.get: fetch current counter value, for example counters.get("visits").
Error code reference▼
CodeHTTPMeaning and remedy
unauthorized401Token is missing, invalid, expired, or the grant has been revoked. Log in again to resolve
forbidden403SDK integration is disabled for this app. Check the SDK settings on your mypage
not_found404Target does not exist, e.g. reading an unsaved key with storage.get
invalid_arg400Invalid argument (key name, value size, type, etc.)
quota_exceeded413 / 429Quota exceeded (413 for storage size / key count, 429 for the app's daily call limit)
rate_limited429Rate limit reached (per-minute / per-day). Retry later
server_error500Server error on the Tsukutta side. Retry later
timeout-Network timeout (raised on the client side)

FAQ

Where do I get the app ID?▼

In My Page, open "Manage / SDK" under your app's card and turn on "SDK integration" — the ID appears there. Copy it before asking an AI to implement, or the work will stall.

Login doesn't work in local development.▼

Add your dev URL (e.g. http://localhost:3000) to "allowed origins". Unregistered origins have the login popup blocked. Don't forget your production domain too.

Can I change the button's design?▼

Use data-theme (light / dark) and data-label. For a fully custom button, call Tsukutta.login() from your own button's click handler.

What user info can I get?▼

The user ID, display name, and avatar URL. No email or other personal data is shared.

What kind of apps can use this?▼

Any app that runs on the web. Plain HTML or frameworks like React/Vue — the same two lines work everywhere.

What else can the SDK do?▼

Cloud save (storage), leaderboards (scores), and counters. See the collapsible sections and the copy-paste sample above for usage.