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#
window.twelvebit?.("signup", { plan: "pro", method: "google" });- Use lowercase snake_case. twelvebit stores other names in that form ("Sign Up!" becomes
sign_up,signupCompletedbecomessignup_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:
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.
<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:
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"}}'| Field | Type | Notes |
|---|---|---|
name | string | Required. Lowercase snake_case, at most 64 characters. |
visitor_id | string | The value of the _tb_vid cookie. |
user_id | string | Your user id. Used when there is no visitor_id: twelvebit finds the visitor that identified with this id. |
props | object | Flat strings, numbers or booleans. |
url | string | The 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:
// 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. Notclick_button_3. - One event per action, with props for variants:
signupwithmethod: "google", notsignup_google. - 3 to 8 goals are enough to start.
- Do not use the reserved names
pageview,identify,outbound,pingorpayment. - 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.