twelvebitDocsllms.txtSign in
View as Markdown

Goals

A goal is an action that matters: signup, trial_started, checkout_started, invite_sent. Goals power conversion rates, funnels and journeys. You can send them from the browser, from HTML attributes, or from your server.

From JavaScript#

js
window.twelvebit?.("signup", { plan: "pro", method: "google" });
  • Use lowercase snake_case. twelvebit stores other names in that form ("Sign Up!" becomes sign_up, signupCompleted becomes signup_completed) and drops a name with no letters.
  • Props are flat: strings, numbers or booleans. Up to 30 props; string values are cut to 255 characters.
  • Send the goal when the action succeeds (after the API call returns), not when the button is clicked.

With a tracking plan, twelvebit codegen writes typed functions, so the names and props always match the plan:

ts
import { track } from "./analytics.gen";

track.signup({ plan: "pro", method: "google" });

From HTML attributes#

No JavaScript needed. Good for links and buttons on marketing pages.

html
<a href="/signup" data-tb-goal="signup_clicked" data-tb-goal-location="hero">Get started</a>
<button data-tb-goal="newsletter_joined" data-tb-goal-list="weekly">Subscribe</button>

data-tb-goal-<name>="value" adds a prop. Hyphens in the name become underscores: data-tb-goal-billing-cycle → billing_cycle.

From your server#

Server events cannot be blocked and are counted even when the browser closes. Send them with a site key:

sh
curl -sS -X POST https://twelvebit.app/api/v1/events -H "Authorization: Bearer $TWELVEBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "subscription_started", "visitor_id": "VISITOR_ID", "props": {"plan": "pro"}}'
FieldTypeNotes
namestringRequired. Lowercase snake_case, at most 64 characters.
visitor_idstringThe value of the _tb_vid cookie.
user_idstringYour user id. Used when there is no visitor_id: twelvebit finds the visitor that identified with this id.
propsobjectFlat strings, numbers or booleans.
urlstringThe page the action belongs to. Optional.

Send visitor_id or user_id. The visitor must be known: the browser script must have sent at least one event for it. Otherwise the API answers 404 with the code visitor_not_found. Read the cookie in your request handler:

ts
// app/api/projects/route.ts (Next.js)
import { cookies } from "next/headers";

export async function POST(req: Request) {
  // … create the project …
  const c = await cookies();
  void fetch("https://twelvebit.app/api/v1/events", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.TWELVEBIT_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({ name: "project_created", visitor_id: c.get("_tb_vid")?.value, props: { template: "blank" } }),
  }).catch(() => {});
  return Response.json({ ok: true });
}

Use a site key (tbk_…) on the server only. With an account token (tbt_…), add ?site=<site id>.

Naming#

  • Past tense or a clear state: signup, trial_started, invite_sent. Not click_button_3.
  • One event per action, with props for variants: signup with method: "google", not signup_google.
  • 3 to 8 goals are enough to start.
  • Do not use the reserved names pageview, identify, outbound, ping or payment.
  • Never put personal data (email, name, phone, free text) in props.

See goals#

The dashboard shows each goal with visitors, completions and attributed revenue. The API has GET /api/v1/goals and the MCP server has list_goals. Funnels can mix pages and goals: GET /api/v1/funnels?steps=page:/pricing,goal:signup.