Quickstart
Adtivity turns your product, payment and on-chain data into a signal you can read, share and act on. There are two ways in — pick the one that matches how you build.
📦 NPM SDK
Drop @adtivity/adtivity-sdk into your web app. Auto-tracks page views, clicks, geolocation and identity with a single init().
🤖 MCP Server
Point Claude, Cursor or any MCP-compatible agent at Adtivity. Query your metrics in plain English — no SDK, no SQL.
Connect MCP →MCP Server Beta
adtivity-mcp is an AI-native setup assistant. Add it once to Claude Code or Cursor, tell your agent “Install Adtivity into this project”, and it detects your framework, installs the SDK, patches your entry file, and verifies the integration — no manual steps, no config wrestling.
Claude Code
Run once in your terminal. Claude Code picks it up on the next session.
claude mcp add adtivity -- npx adtivity-mcpTo use it across all your projects, add it globally:
claude mcp add --scope user adtivity -- npx adtivity-mcpCursor / Claude Desktop / Windsurf
Add to ~/.cursor/mcp.json (or the project-level .cursor/mcp.json):
{
"mcpServers": {
"adtivity": {
"command": "npx",
"args": ["adtivity-mcp"]
}
}
}Five tools, one prompt
When you say “Install Adtivity”, the agent runs these tools in order:
| Tool | What it does |
|---|---|
adtivity_detect_framework | Reads package.json — identifies Next.js App/Pages Router, React, Vue, Express, or React Native and finds the right entry file. |
adtivity_install_sdk | Runs npm/yarn/pnpm/bun install @adtivity/adtivity-sdk using your detected package manager. |
adtivity_write_init_code | Creates AdtivityProvider.tsx (Next.js App Router) or patches your entry file with init(), initPageTracking(), and initClickTracking(). |
adtivity_wrap_event | Returns a ready-to-paste trackEvent() snippet for any named action — signup, upgrade, checkout, and more. |
adtivity_verify_integration | Checks SDK installed, init code present, and API key configured. Returns a pass / warn / fail checklist. |
Quick test
Confirm the server starts before adding it to your AI client:
npx adtivity-mcpThe process will hang — that means it's listening on stdio and is ready. Press Ctrl+C to exit.
Once connected to Claude Code or Cursor, open any project and try the prompt below. The demo shows you exactly what the agent will do:
Click “Run demo” to see what happens when you ask your AI to install Adtivity.
Prompts that work well
After setup, you can also use the MCP tools individually:
| Prompt | What happens |
|---|---|
| “Install Adtivity into this project” | Runs all five tools in sequence — detect, install, init, verify. |
| “Add Adtivity event tracking to my checkout button” | Calls adtivity_wrap_event and pastes the snippet into your component. |
| “Is Adtivity set up correctly in this project?” | Runs adtivity_verify_integration and reports the checklist. |
| “What framework is this project using?” | Calls adtivity_detect_framework and summarises the result. |
signup-cta-hero vs btn-1 changes whether your agent can answer “how is the hero CTA doing?”.Installation
Install the Adtivity SDK from npm. The package name is @adtivity/adtivity-sdk — note the double adtivity.
npm install @adtivity/adtivity-sdkReact Native — also install the async storage peer dependency:
npm install @react-native-async-storage/async-storageThe SDK ships as a single isomorphic package for both browser and React Native environments.
Authentication
The Adtivity SDK authenticates with a single API key. There's no separate sign-in step or token exchange — the key you pass to init() identifies your project for every event the SDK sends.
Find your key in Settings → API Keys in the Adtivity dashboard. Expose it to your client through a public env var, e.g. NEXT_PUBLIC_ADTIVITY_API_KEY.
Initialization
Initialise the SDK once at app startup. In Next.js this goes in your root layout or _app.tsx; in React, in your top-level component.
Basic setup
Import the SDKimport {
init,
initClickTracking,
initPageTracking,
initLocationTracking,
} from "@adtivity/adtivity-sdk";Initialise inside useEffectuseEffect(() => {
if (typeof window === "undefined") return;
if (window.__ADTIVITY_BOOTSTRAPPED__) return;
window.__ADTIVITY_BOOTSTRAPPED__ = true;
const API_KEY = process.env.NEXT_PUBLIC_ADTIVITY_API_KEY;
if (!API_KEY) {
console.error("Adtivity SDK: API key is not configured");
return;
}
init({
apiKey: API_KEY,
debug: false,
// Optional tuning:
// batchSize: 10,
// flushInterval: 5000,
});
initPageTracking();
initClickTracking();
initLocationTracking();
}, []);Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | — | Required. Your project key from Settings → API Keys. |
apiBaseUrl | string | Adtivity default | Override the backend endpoint. |
debug | boolean | false | Logs all SDK activity to the console. Use during development. |
batchSize | number | 10 | Events to collect before an automatic flush. |
flushInterval | number | 5000 | Milliseconds between automatic flushes. |
maxRetries | number | 3 | How many times to retry a failed batch. |
retryDelayMs | number | 1000 | Base delay for exponential backoff retries (doubles each attempt). |
collectData | boolean | true | Master switch — set false to start with all tracking off. |
Click Tracking
Once initClickTracking() is running, Adtivity listens for any element marked with a data-adtivity-* attribute. No onClick handlers, no manual track() calls.
General click tracking
Use data-adtivity-track on any clickable element.
<div data-adtivity-track="feature-card-click">
Click me
</div>Buttons
For <button> elements, use the more specific data-adtivity-button-track.
<Button data-adtivity-button-track="web3-simulate-token-transfer">
<Rocket className="mr-2 h-5 w-5" />
Simulate Token Transfer
</Button>Links
For navigation, use data-adtivity-link-track.
<Link href="/cars" data-adtivity-link-track="header-nav-cars">
<Car className="mr-2 h-4 w-4" />
Cars
</Link>Custom properties
Attach arbitrary JSON with data-adtivity-props.
<button
data-adtivity-button-track="add-to-cart"
data-adtivity-props='{"productId": "123", "price": 49.99}'>
Add to Cart
</button>signup-button-click is far more useful in your dashboard (and to your AI agent) than btn1.Page Tracking
Once initPageTracking() is running, Adtivity fires a “Page Viewed” event automatically. Duplicate URLs are deduplicated — if the URL has not changed, no event fires. Not available in React Native.
| Trigger | When it fires |
|---|---|
| Initial load | When the user first lands on your site. |
history.pushState | Client-side navigation in React Router, Next.js App Router, etc. |
history.replaceState | URL replacement without adding a history entry. |
popstate | Browser back / forward navigation. |
Properties captured on every page view:
| Property | Description |
|---|---|
pageTitle | document.title |
path | window.location.pathname |
query | window.location.search |
fullUrl | window.location.href |
Location Tracking
Calling initLocationTracking() enriches every event with geolocation derived from the visitor's IP address — country, region, city. No browser permission prompt; it's resolved server-side.
| Field | Description |
|---|---|
country | ISO country code, e.g. “US”. |
region | State or province. |
city | City-level location. |
ip_address | Visitor's public IP address. |
These fields are promoted to top-level in the API payload. Works in both browser and React Native.
Identity
The SDK gives you three layers of identity: anonymous ID (free), session ID (free), and user ID (one identify() call). Together they let Adtivity stitch a complete journey from first visit through sign-in and beyond.
Anonymous ID
An auto-generated UUID stored in localStorage, created the first time a visitor hits any page where the SDK is initialised. It persists across sessions, so a returning visitor on the same browser keeps the same anonymous ID.
// Automatically handled by the SDK.
// No code needed — created on first visit.Session ID
A separate identifier scoped to a single browser tab. Open your site in a new tab and you get a new session ID; close the tab and that session ends.
Automatic// Automatically handled by the SDK.
// New session per tab/window.User ID (custom)
When a user signs in, call identify(userId, properties?) with your own user ID. It is sent immediately — not batched. After this call, user_id is attached to all subsequent events for the session.
import { identify } from "@adtivity/adtivity-sdk";
identify("user_12345", {
email: "user@example.com",
plan: "pro",
signupDate: "2025-01-01",
});Web3 / wallet identity
Use setWallet(address, chainId?) when a user connects a wallet. Both fields are automatically included on every subsequent event — trackEvent, identify, and trackTx alike. Pass null to clear on disconnect.
import { setWallet, identify } from "@adtivity/adtivity-sdk";
setWallet("0x742d35Cc...", "1"); // address, chainId
identify("0x742d35Cc..."); // use wallet as user ID
// On disconnect
setWallet(null);Common chainId values: “1” Ethereum · “137” Polygon · “56” BNB Chain · “8453” Base · “42161” Arbitrum.
Tracking blockchain transactions
Use trackTx(name, properties?) for on-chain transactions.transaction_hash and contract_address are promoted to top-level fields in the API payload (not nested inside properties).
import { trackTx } from "@adtivity/adtivity-sdk";
trackTx("NFT Minted", {
transaction_hash: "0xdef...789",
contract_address: "0x123...456",
token_id: "42",
price_eth: "0.08",
});Auto-Captured Data
Every event Adtivity sends — page view, click, identify — is automatically enriched with the following context. You don't need to attach any of it manually.
| Group | Fields |
|---|---|
| Time & URL | ISO 8601 timestamp · current URL with query · referrer |
| Device | User agent · browser · device type · OS |
| Location | Country · region · city · anonymised IP (needs initLocationTracking) |
| Identity | Anonymous ID · session ID · user ID & wallet (if identify'd) |
| Element | Element ID · text · tag · href · CSS classes · form values (for click events) |
Events
An event is a single thing that happened — a page view, a click, an identify call, a wallet connect. Every event captured by the SDK gets enriched with the auto-captured context above and lands in your Adtivity workspace ready to query.
You don't compose events manually. The SDK produces them from data attributes on your markup and from the init* functions you call once at startup.
Companies
A company is the workspace that owns your data. One Adtivity account can have multiple companies — useful if you ship more than one product, or want a clean split between staging and production. Each company has its own API key and dashboard.
Set up a new company from Settings → Companies → New.
Users
A user is anyone whose journey Adtivity has stitched together. On first visit they exist as an anonymous ID; the moment you call identify() with a userId, email, or wallet address, anonymous activity gets merged into the known user record. See Identity for how to wire that up.
Lifecycle
Adtivity automatically classifies users by where they sit in your funnel — visitor, signup, activated, paying, churned — by reading the events you're already sending. The Lifecycle Chart on your dashboard is the canonical view; the same buckets are queryable through the MCP server.
Stripe Integration
Connect Stripe from Settings → Connections — about 90 seconds. Once connected, MRR, ARR and churn auto-populate in your dashboard and become queryable through the MCP server. No manual event tracking required for revenue.
Paystack Integration
Processing payments in Africa? Connect Paystack the same way — Settings → Connections. Stripe and Paystack can be active in the same workspace; revenue from both is unified into a single MRR view.
Wallet Monitoring — No SDK Required
You don't need the SDK to track on-chain activity. Register any wallet address in the Web3 Wallets section of your company dashboard and Adtivity monitors it at the backend level — no MetaMask, no ethers.js, no SDK integration.
| Endpoint (backend) | What it returns |
|---|---|
GET /wallets/connections/{id}/analytics | Total txns, volume, unique tokens, inflow/outflow, gas, top tokens |
GET /wallets/connections/{id}/recent?hours=24 | Transactions in the last N hours |
GET /wallets/connections/{id}/activities | Paginated full transaction history |
GET /wallets/balance?wallet_address=…&network=… | Current balance and token holdings |
trackTx() and setWallet() capture user-triggered on-chain actions from your frontend. Wallet monitoring tracks the registered address itself via backend indexing — it works even if you have no SDK installed.Privacy & Consent
Call setConsent(false) when a user opts out. This stops all future event tracking, flushes and clears the event queue, and removes persisted events from localStorage. Call setConsent(true) to re-enable.
import { setConsent } from "@adtivity/adtivity-sdk";
// User opts out
setConsent(false);
// User opts back in
setConsent(true);You can also start with all tracking off by passing collectData: false to init().
Runtime Configuration
Swap the API key or backend URL after init — useful when users switch workspaces or when you point to a different environment at runtime.
import { setApiKey, setBaseUrl } from "@adtivity/adtivity-sdk";
// After user logs into a different workspace
setApiKey("new-api-key");
// Point to a different backend
setBaseUrl("https://your-custom-backend.com");React Native
The SDK is React Native compatible. Because AsyncStorage reads are asynchronous, call waitUntilReady() before tracking to ensure the anonymous ID and session ID have loaded from storage.
import { init, waitUntilReady, trackEvent, setWallet } from "@adtivity/adtivity-sdk";
init({ apiKey: "your-api-key" });
await waitUntilReady(); // wait for AsyncStorage IDs to load
trackEvent("App Opened");
setWallet("0xabc...", "1");| Feature | Browser | React Native |
|---|---|---|
trackEvent | ✓ | ✓ |
trackTx | ✓ | ✓ |
identify | ✓ | ✓ |
setWallet | ✓ | ✓ |
initPageTracking | ✓ | — |
initClickTracking | ✓ | — |
initLocationTracking | ✓ | ✓ |
waitUntilReady | no-op | Required |
REST API Coming soon
A public REST surface is on the roadmap for teams that want to read Adtivity data outside of the dashboard or the MCP server — for internal tools, custom dashboards, or scheduled exports. Endpoints, auth model, and rate limits will be documented here once it lands.
Until then, the MCP server is the supported way to query your data programmatically.
SDK Reference
Quick index of every public function in @adtivity/adtivity-sdk:
| Export | Signature | What it does |
|---|---|---|
init | (config) => void | Initialize the SDK. Singleton — safe to call multiple times. |
trackEvent | (name, props?) => void | Track a custom event. Batched and retried automatically. |
trackTx | (name, props?) => void | Track a blockchain transaction. Promotes transaction_hash and contract_address to top-level. |
identify | (userId, props?) => void | Identify a user. Sent immediately, not batched. |
setWallet | (address, chainId?) => void | Attach wallet address and chain ID to all subsequent events. Pass null to clear. |
initPageTracking | () => void | Enable automatic page view tracking. Browser only. |
initClickTracking | () => void | Enable automatic click tracking via data-adtivity-* attributes. Browser only. |
initLocationTracking | () => void | Enable IP-based geolocation. Browser + React Native. |
setConsent | (bool) => void | Enable or disable all data collection. false flushes and clears the queue. |
setApiKey | (key) => void | Update API key at runtime. |
setBaseUrl | (url) => void | Update backend URL at runtime. |
waitUntilReady | () => Promise<void> | Wait for async ID init. Required in React Native; no-op in browser. |
Event Schema
Every event the SDK produces ships with the same envelope of auto-captured fields. The full reference is in Auto-Captured Data; the short version:
All events are sent as a JSON array to POST /sdk/event with an X-API-Key header. Top-level fields (wallet_address, chain_id, transaction_hash, contract_address, country, region, city, ip_address) are always promoted out of properties. Null and empty-string values are omitted.
{
"type": "track",
"eventName": "Token Swap",
"timestamp": "2025-06-23T12:00:00.000Z",
"anonymous_id": "uuid-v4",
"session_id": "uuid-v4",
"user_id": "user_abc123",
"wallet_address": "0xabc...def",
"chain_id": "1",
"transaction_hash": "0xdef...789",
"contract_address": "0x123...456",
"country": "US",
"region": "California",
"city": "San Francisco",
"ip_address": "203.0.113.1",
"properties": {
"url": "https://app.example.com/swap",
"referrer": "https://app.example.com/",
"userAgent": "Mozilla/5.0...",
"amount": "100",
"token": "USDC"
}
}| Field | Type | Description |
|---|---|---|
type | string | Always “track”. |
eventName | string | The name you passed to trackEvent() or trackTx(). |
timestamp | ISO 8601 | When the event fired. |
anonymous_id | string | Per-visitor UUID, persisted in localStorage / AsyncStorage. |
session_id | string | Per-tab / per-session identifier. |
user_id | string | Set after identify(). |
wallet_address | string | Set after setWallet(). |
chain_id | string | Chain ID passed to setWallet(). |
transaction_hash | string | From trackTx() — promoted to top-level. |
contract_address | string | From trackTx() — promoted to top-level. |
country / region / city / ip_address | string | From initLocationTracking() — promoted to top-level. |
properties | object | All remaining custom and auto-captured fields (URL, referrer, user agent, element data). |
Best practices
A few things worth doing on day one:
- Name events for humans, not machines. Your dashboard, your team, and your AI all read these.
- Identify users early. Call
identify()the moment auth resolves so the anonymous → known stitch happens cleanly. - Turn on
debug: truelocally. You'll see every event in the console while you wire things up. - Keep the public key public, the server key private. They're separate by design.
Next: Connect MCP → · Plug in Stripe → · Web3 identity →