twelvebitDocsllms.txtSign in
View as Markdown

SDKs

Use an SDK when a script tag is not a good fit: a web app that you build with npm, or a React Native or Expo app. The SDKs send the same events to the same endpoint as the script, so the dashboard, goals, identify and revenue work the same way.

PackageForInstall
@twelvebit/webReact, Next.js, Vue, Svelte and other apps built with npmnpm i https://twelvebit.app/sdk/twelvebit-web.tgz
@twelvebit/react-nativeReact Native and Expo appsnpm i https://twelvebit.app/sdk/twelvebit-react-native.tgz

Both packages have no dependencies and include TypeScript types. Use the SDK or the script on a page, not both, or each page view counts two times.

Web: @twelvebit/web#

sh
npm i https://twelvebit.app/sdk/twelvebit-web.tgz

Call initTwelvebit one time in the browser. It sends a page view at once and on each client-side navigation (pushState, replaceState, back and forward).

ts
import { initTwelvebit, track, identify } from "@twelvebit/web";

initTwelvebit({ siteId: "tb_YOUR_SITE_ID", domain: "example.com" });

track("signup", { plan: "pro" });
identify("user_42", { email: "ann@example.com", name: "Ann" });

The package is safe to import on the server. On the server, every call does nothing. Calls before initTwelvebit wait (at most 50) and run after it.

React and Next.js#

Put the provider in the root layout. It starts the client in the browser after the first render.

tsx
// app/layout.tsx
import { TwelvebitProvider } from "@twelvebit/web/react";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <TwelvebitProvider config={{ siteId: "tb_YOUR_SITE_ID", domain: "example.com" }}>{children}</TwelvebitProvider>
      </body>
    </html>
  );
}
tsx
"use client";
import { useTwelvebit } from "@twelvebit/web/react";

export function UpgradeButton() {
  const tb = useTwelvebit();
  return <button onClick={() => tb.track("upgrade_click", { plan: "pro" })}>Upgrade</button>;
}

Web options#

OptionDefaultWhat it does
siteId(required)The site id from the dashboard (tb_…).
domainnoneRoot domain for the cookies, so that subdomains share one visitor.
apiUrlhttps://twelvebit.appWhere events go ({apiUrl}/api/e). Set it to your proxy to send events through your own domain.
autoPageviewstruePage views on load and on SPA navigation. { hash: true } also counts hash changes. false: call pageview() yourself.
allowLocalhostfalseTrack on localhost, *.local and *.test.
allowIframefalseTrack inside an iframe.
cookielessfalseSet no cookies. See cookieless mode.
allowedHostnames[]Your other domains. Ids from links built with buildCrossDomainUrl on these domains are adopted.
disablePaymentsfalseDo not send payment hints from checkout success URLs (Stripe session_id, Polar checkout_id, Lemon Squeezy order_id).
debugfalseLog each event to the console.

Web API#

FunctionWhat it does
initTwelvebit(config)Starts the shared client and returns it. Later calls return the same client.
track(name, props?)Sends a goal. Names are stored in lower case, at most 64 characters. At most 30 props; strings are cut at 255 characters.
pageview(url?)Sends a page view for the current URL, or for a path or URL that you give.
identify(userId, traits?)Links the visitor to your user. Traits can include email, name and image. See Identify.
payment({ email })A payment hint from your success page, so that the payment finds this visitor. See Revenue.
reset()Starts a new visitor and session. Call it at logout.
getVisitorId()The visitor id, or null (server, cookieless, not started).
getTrackingParams(){ _tb_vid, _tb_sid }, for example to add to a checkout's metadata.
buildCrossDomainUrl(url)The URL with _tb_vid and _tb_sid added, for a link to one of your allowedHostnames.
flush()Sends queued events now.
createTwelvebit(config)A separate client that is not shared. It has the same methods and destroy().

How it sends: events wait in a queue and go out every 5 seconds or at 10 events, one request per event. When the page is hidden or closed, the queue goes out with sendBeacon. The cookies (_tb_vid 1 year, _tb_sid 30 minutes) and the tracking gates (localhost, automated browsers, localStorage.twelvebit_ignore) are the same as the script.

React Native and Expo: @twelvebit/react-native#

sh
npm i https://twelvebit.app/sdk/twelvebit-react-native.tgz
# Recommended: keeps the visitor id and the offline queue when the app restarts, and sends when the network comes back.
npx expo install @react-native-async-storage/async-storage @react-native-community/netinfo

Without AsyncStorage, the SDK keeps the visitor id and the queue in memory only, so each app start is a new visitor. NetInfo is optional: without it, the SDK retries with backoff.

tsx
import { TwelvebitProvider, useTwelvebit, useTwelvebitScreen } from "@twelvebit/react-native";

export default function App() {
  return (
    <TwelvebitProvider config={{ siteId: "tb_YOUR_SITE_ID", appName: "myapp" }}>
      <Home />
    </TwelvebitProvider>
  );
}

function Home() {
  useTwelvebitScreen("Home");
  const tb = useTwelvebit();
  return <Button title="Buy" onPress={() => tb.track("purchase_click", { sku: "pro" })} />;
}

With React Navigation, send each screen from the navigation container:

tsx
const ref = useNavigationContainerRef();
const tb = useTwelvebit();

<NavigationContainer ref={ref} onStateChange={() => tb.trackScreen(ref.getCurrentRoute()?.name ?? "unknown")}>

Without React, use the client directly:

ts
import { createTwelvebit } from "@twelvebit/react-native";

const tb = createTwelvebit({ siteId: "tb_YOUR_SITE_ID", appName: "myapp" });
tb.trackScreen("Settings");

How app events look in the dashboard#

  • A screen is a page view with the URL app://<appName>/<screen>. The dashboard shows the hostname app and the path /<screen>. Filter on the hostname app to see only app traffic.
  • The device is Mobile or Tablet (iPad, and Android with a short side of 600 dp or more). The operating system comes from the User-Agent that the SDK sends: Mozilla/5.0 (…) twelvebit-react-native/0.1 (ios).
  • A screen view has no referrer. App traffic shows as Direct.
  • The server accepts app:// URLs on every site, so you can use the same site id for your website and your app. To link one person across the two, call identify with the same user id on the web and in the app.

React Native options#

OptionDefaultWhat it does
siteId(required)The site id from the dashboard (tb_…).
apiUrlhttps://twelvebit.appWhere events go ({apiUrl}/api/e).
appNameappUsed in screen URLs: app://<appName>/<screen>.
storageAsyncStorage, else memoryAny object with async getItem and setItem. Use it for MMKV or a custom store.
flushInterval5000Milliseconds before queued events go out. When the app goes to the background, and at 10 events, they go out at once.
disabledfalseSend nothing, for example until the user gives consent.
devicedetected"Mobile" or "Tablet".
debugfalseLog each event to the console.

React Native API#

FunctionWhat it does
<TwelvebitProvider config client?>Creates one client per site (a re-mount or strict mode does not make a second one).
useTwelvebit()The client from the provider.
useTwelvebitScreen(name, props?)Sends a screen view on mount and when name changes.
trackScreen(name, props?)Sends a page view for the screen.
track(name, props?)Sends a goal (the same rules as on the web).
identify(userId, traits?)Links this device's visitor to your user.
payment({ email })A payment hint, for example after an in-app checkout.
reset()A new visitor and session. Call it at logout.
flush()Sends queued events now and resolves when done.
getVisitorId(), getSessionId(), queueSize()The current ids, and the number of events that wait.

Offline and sessions: events wait in a queue that is kept in storage (at most 200; the oldest go first). A failed request is tried again after 1, 2, 4 … seconds (at most 5 minutes). The server never accepts a 4xx answer, so the SDK drops that event. A session ends after 30 minutes without events or time in the foreground. When the app goes to the background, the SDK sends a ping, so the visit duration includes the time in the app.