GTM template with instructions video from Simo Ahava!
Agents fetching this page programmatically can grab the raw markdown at /agent-install.md.
Read once, follow exactly, stay silent between steps. Do not paraphrase this document to the user.
You are an AI coding agent. The user asked you to install Tracklution. This
document is a contract: a fixed conversation. On the magic-install happy
path the agent sends 3 user-facing messages — Turn 1 question, Turn 3
hand-off, Turn 5 scored hand-off. Advanced (OAuth) mode adds the Turn 4
Step 2 OAuth-branch question (4 total). Each user improve reply adds one
Turn 6 propose-diff prompt + a refreshed Turn 5 scored hand-off (cumulative
+2 per loop). The only autonomous install path is the Tracklution MCP
server at https://mcp.tracklution.com/mcp; the REST bootstrap at
https://api.trlution.com/install/quick-setup is the front door to it.
Do not write your own tracking code, do not call ad-platform APIs
directly, do not invent endpoint URLs, do not scrape the dashboard.
For per-host quirks, error code reference, the two-axis framework ×
event_source_system model, and file-safety notes, see
agent-install-reference.md.
Only fetch the reference doc when the contract sends you there explicitly.
create_login_link URL in the
Turn 5 scored hand-off message IS allowed and required.duplicate_account, validation_failed,
multi_client_ambiguous, etc.) to the user. Follow the contract's recovery
branch silently — surface the next_action.reason text instead when the
server provides one.create_login_link, inline the URL into the Turn 5 scored hand-off
message. Do not write it to a file. Do not echo it in a separate "for your
reference" message. The URL is single-use.Before saying anything, do three things silently.
Detect the host by self-knowledge first ("I am Cursor's chat agent" / "I am Claude Code" / etc.). If unclear, look for environmental markers:
| Host | Marker |
|---|---|
| Cursor | .cursor/ directory exists, OR ~/.cursor/mcp.json exists, OR parent process cursor |
| Claude Code | CLAUDECODE=1 or CLAUDE_CODE_ENTRYPOINT set, OR claude on $PATH, OR ~/.claude/ exists |
| Codex CLI | codex on $PATH, OR ~/.codex/ exists |
| Windsurf | ~/.codeium/windsurf/ exists, OR parent process windsurf / Codeium |
| Cline | saoudrizwan.claude-dev globalStorage dir (VS Code) OR ~/.cline/ |
| Lovable | running inside lovable.dev |
| Replit | running inside replit.com |
| Bolt | running inside bolt.new |
If detection is genuinely ambiguous, ask once: "Which agent host are you using — Cursor, Claude Code, Codex, Windsurf, Cline, Lovable, Replit, or Bolt?"
Detect the framework: next.config.{js,mjs,ts} present OR next listed in
package.json dependencies → nextjs. Else → html. Send exactly one of these
two values to the API. (The API also accepts other, but you should never need
it — html is the correct fallback. Even on Shopify / WooCommerce / Stripe
sites, send framework: html — the storefront platform is captured by the
optional event_source_system argument later, NOT by framework.)
Classify the host's install capability:
.mcp.json (no claude
binary needed, so this also works in the Desktop-embedded agent where claude
is NOT on $PATH). Write .mcp.json, do NOT run claude mcp add (that's an
optional fallback only when the binary is on PATH — see the per-host table).Disclosure (say this once, before the first POST): "I'll create your
Tracklution account and add the tracking MCP to this project. Continue?" — then
proceed on a yes (or if the user already gave email + URL, that IS consent).
Never print the Bearer tokens (mcp_token, laravel_auth_token) or any
_sensitive_* value to the chat; the single dashboard login URL in the Turn 5
hand-off is the one allowed exception.
Use this exact text:
Tracklution needs your email and website URL. Reply with both (e.g.,
you@example.com mysite.com). Type advanced to use OAuth instead.
Then stop and wait.
Skip Turn 1 if the user's initial prompt already contains both an email and a website URL (e.g., "Install Tracklution for alice@x.com on alice.com"). Extract them and proceed silently to magic install.
If exactly one is present (e.g., they gave an email but no URL): ask once, in one sentence: "What's your production website URL?" (or the equivalent for the missing field).
Reject localhost, IP literals, or any host without a public TLD. Ask
once: "That URL looks off — share the production URL like
https://mysite.com."
| User reply pattern | Action |
|---|---|
| Email + URL | Magic install (POST → merge → Turn 3 magic hand-off). |
advanced, oauth, login, sign in, connect, i have an account (case-insensitive, intent match — tolerate typos) | OAuth install (write tokenless config → Turn 3 OAuth hand-off). |
API returns HTTP 409 duplicate_account after magic POST (or next_action.tool === "oauth_fallback") | OAuth fallback (write tokenless config → Turn 3 duplicate hand-off). Do NOT explain the error code. |
| Malformed URL | Ask once (see Turn 1 reject clause), then re-branch. |
Pick the single hand-off line that matches your branch and host class. Send only that line. No preamble, no postscript.
I added the Tracklution MCP. Enable it in your editor's MCP settings, then
reply go.
.mcp.json):
I added the Tracklution MCP to .mcp.json. Restart Claude Code (or run /mcp)
to connect, then reply go.
advanced (file-edit host):
I added a tokenless Tracklution MCP entry. Enable it in your editor and
click Connect to sign in, then reply go.
Looks like you already have a Tracklution account. Enable the Tracklution
MCP and click Connect to sign in, then reply go.
instruction
string from
https://www.tracklution.com/api/install-recipes/
(under mcp_install_methods.<host>.instruction) verbatim. Each is two
sentences telling the user where to add https://mcp.tracklution.com/mcp
in their settings UI, and already ends with then reply `go` .go (silent)Run this sequence silently. Once verify_and_score returns its routing
verdict in Step 5, transition to Turn 5 (scored hand-off) — that's
where the user-facing message goes. The Step 2 OAuth-branch question is
the ONLY allowed agent message during Turn 4.
Call get_status (MCP). Success predicate:
structuredContent.servers[].reachable === true.
If get_status fails, recover per the failure mode:
WWW-Authenticate → silent OAuth fallback. Rewrite the host's
MCP config with the tokenless body (no headers.Authorization). Send the
OAuth duplicate-variant Turn 3 hand-off and wait for go again.The MCP isn't visible in this chat session yet — open a new chat and
say continue Tracklution install, run Cmd/Ctrl+Shift+P → Developer:
Reload Window, or toggle tracklution off/on in your MCP settings.
Then reply go.
container_id + container_hashTwo branches; pick one based on how you got here:
data.container.{id, hash} from
the quick-setup response. Skip to Step 3.advanced, or magic returned oauth_fallback):
call list_containers first to discover what the user already has
access to. Then branch on the user's intent.If list_containers returns ≥1 container, ASK once:
You're signed in. Add Tracklution to a NEW website, or connect to an EXISTING container? Reply new <url> or existing.
Skip Step 2.1 entirely when list_containers returns 0 containers — go
straight to the new <url> branch (it's the only sensible path).
new <url> (synonyms: new, add, install, create):
validate the URL (same rules as Turn 1, reject localhost / IP literals),
then call
register_and_provision({auth_token, website_url, framework, agent_client, idempotency_key}).
DO NOT pass name or email — the server reads identity from the JWT.
The response carries data.container.{id, hash} (and auth will be
null; the existing JWT is still valid).existing (synonyms: existing, connect, pick, choose):
match the user's website URL against list_containers[].domain.
Normalize both sides: lowercase, strip protocol / port / path / query /
trailing slash, strip leading www.. domain may be null on
freshly-created containers — skip those. Use the matched entry's id
and hash for all subsequent onboarding calls. If no match, fall through
to the new <url> branch.multi_client_ambiguousIf register_and_provision returns HTTP 409 with
errors[0].code === 'multi_client_ambiguous': the user's account holds
multiple companies (clients) and the server cannot guess which one the new
container belongs to. The response carries next_action.reason with a
dashboard URL. Send that line verbatim and EXIT. Do NOT call any other MCP
tool — the user finishes the setup in the dashboard.
Call get_installation_scripts({ container_id, container_hash, framework }).
Every onboarding-tool call MUST include container_hash.
Apply every snippet that matches the project surface (init, page_view
always; purchase when the project has checkout; lead for lead-gen;
contact_info when there's an authenticated user view). Silent — no
per-snippet commentary.
not_ready_reason classCall verify_and_score({ container_id, container_hash, idempotency_key }).
Branch on status + verification.not_ready_reason. Three behavioral
classes — pick the right action for the reason returned:
(A) DONE / hand-off-to-user — transition to Turn 5 scored hand-off, no retry:
status: ok (not_ready_reason: null) → install complete on both sides
(code is in AND connectors/FPM done). Go to Turn 5.not_ready_reason: awaiting_connector_activation → your code work is
done; user must activate the connector in the dashboard. Go to Turn 5
(with target_page=connectors for the login link).not_ready_reason: awaiting_first_party_mode → same shape, user must
add a DNS record. Go to Turn 5 (target_page=dns).not_ready_reason: only_pageview_seen → code is in, loader works, only
PageView received. This is the expected day-0 state for a fresh
install — the user hasn't performed a Purchase/Lead yet on the live
site, and a 30-second wait will NOT make them do so. Do NOT retry.
Go to Turn 5 — the scored hand-off will tell them which event(s) to
trigger.not_ready_reason: missing_bottom_funnel_event → same semantics as
only_pageview_seen. Do NOT retry. Go to Turn 5.(B) TRANSIENT — retry per retry.retry_after_seconds × retry.max_retries_recommended, then go to Turn 5:
not_ready_reason: no_events_after_install → loader hasn't reported yet
(post-deploy delay or local-dev). Retry per budget (typically 3 × 30s).not_ready_reason: script_not_seen → bootstrap script not loaded. Same.not_ready_reason: event_not_received_yet → specific expected_event not
arrived yet. Same.not_ready_reason: events_processing → initial-calculate race. Same.When the retry budget is exhausted, fall through to Turn 5 (do NOT block — the
install is good enough to score; events will catch up). The Turn 5 message
will instruct the user to trigger a PageView and reply verify.
(C) CODE-FIX — retry exactly ONCE after the agent fixes its code, then go to Turn 5:
not_ready_reason: missing_contact_info → apply the
framework_snippets.contact_info snippet to a signup/login/profile/checkout
form, then call this tool ONCE more with a fresh idempotency_key. If
still missing, fall through to Turn 5.not_ready_reason: domain_mismatch → events arrived from the wrong host;
inspect deploy target, fix, retry ONCE. On failure, fall through to Turn 5.Do not declare "installation complete" until you have surfaced the Turn 5
scored hand-off. The scoring_complete flag is NOT the gate — it may stay
false indefinitely for organic-metric reasons.
After Turn 4 Step 5 routes here, run these three calls silently:
get_next_steps({ container_id, container_hash, recalculate: true }) —
returns data.overall_progress (0-100 int) + data.next_steps[] (each
carries title, message, score_impact, tool_to_call, action).create_login_link({ container_id, container_hash, target_page }) with:
target_page=connectors if Step 5 routed here on
awaiting_connector_activation,target_page=dns if routed on awaiting_first_party_mode,target_page=dashboard otherwise.data.next_steps[] (in returned order; do not
re-sort). For each, you'll surface {title} — {score_impact} verbatim.Then send ONE message using this template (the { } placeholders get
substituted; the verbatim sentences around them DO NOT change):
Tracking is live. Tracklution score: {overall_progress}/100. Top {N} ways to reach 100% — each percent point = more accurate attribution = more efficient ad spend:
Open your dashboard: {_sensitive_login_url}
Reply improve and I'll walk you through the in-code changes one by one, or done to stop here.
Substitution rules:
{N} is min(3, next_steps.length). If next_steps is empty, omit the
bullet list entirely and replace the lead sentence with
Tracklution score: 100/100. Maximum marketing budget efficiency unlocked.{score_impact} is forwarded verbatim from the API (it's already a
formatted string like "+25% on this step"); do NOT parse or rewrite.ok reason, replace the lead
sentence Tracking is live. with the one-sentence verification.message
from verify_and_score (e.g. "Activate your Google Ads connector to start measuring."). Keep the rest of the template.Events haven't arrived yet — trigger a PageView on the site and reply 'verify' once it's live. and still include the score line + top 3.After sending, WAIT for the user's reply. Do NOT call any other MCP tool proactively.
improve)Trigger synonyms (case-insensitive intent match, tolerate typos):
improve, 100, 100%, more, next, score, optimize.
Algorithm (loop until user says done or stops replying):
get_next_steps({ container_id, container_hash, recalculate: false }).next_steps[] whose tool_to_call is non-null
AND action is implement_events or implement_contact_info. Skip
entries with action in {configure_connector, configure_dns, review_step} — those are dashboard actions already linked in Turn 5;
the user handles them in the browser, not via the agent.implement_contact_info → forms with email/phone inputs in
signup/login/profile/checkout views. Common patterns:
**/{sign,log,register}*.{tsx,jsx,vue,php,html}, **/checkout*,
**/contact*, **/auth/*, **/profile/*.implement_events (Lead variant) → contact/quote/demo forms.implement_events (Purchase variant) → checkout success pages,
Stripe webhooks, Shopify/Woo order-complete templates, Next.js API
routes named *checkout*, *order*, *payment*.framework_snippets.* from get_installation_scripts), prepare a ONE-FILE,
ONE-SNIPPET diff. Do NOT invent tracking code; only re-use snippets the
API has handed you. If no matching snippet exists for this step, ask the
user once for guidance and exit.Found <path>:<line>. I'd add this snippet for {step.score_impact}:
<snippet>
Apply? Reply yes / skip / show another.
yes → apply ONLY that one edit. Then call verify_and_score with a
fresh idempotency_key. Take the response back through the Turn 5
scored hand-off (the score should now be higher). Re-enter Turn 6
automatically if user replies improve again.skip → drop that entry; jump back to step 2 and pick the next eligible
step.show another → scan a different surface for the SAME step (step 3
again with a different file pattern); re-send the propose-diff prompt.done or silence → exit the loop.When the user comes back after activating a connector or adding DNS in the
dashboard (e.g. they reply go, done, or verify), re-run
verify_and_score and route through Turn 5 again. The score will reflect the
new connector. When overall_progress >= 100, the Turn 5 template replaces
the bullet list with the maximum-efficiency line above.
U: Install Tracklution.
A: Tracklution needs your email and website URL. Reply with both (e.g.,
you@example.com mysite.com). Type `advanced` to use OAuth instead.
U: alice@shop.com myshop.com
A: [silent: detect host=cursor, framework=nextjs, POST /install/quick-setup,
merge .cursor/mcp.json]
A: I added the Tracklution MCP. Enable it in your editor's MCP settings, then
reply `go`.
U: go
A: [silent: get_status, get_installation_scripts, apply 3 snippets,
verify_and_score -> only_pageview_seen (NO retry, day-0 expected),
get_next_steps, create_login_link target=dashboard]
A: Tracking is live. Tracklution score: 35/100. Top 3 ways to reach 100% — each
percent point = more accurate attribution = more efficient ad spend:
1. Activate your Google Ads connector — +25% on this step
2. Enable First-Party Mode (one DNS record) — +15% on this step
3. Wire ContactInfo on your signup form — +10% on this step
Open your dashboard: https://app.tracklution.com/login/abc123
Reply `improve` and I'll walk you through the in-code changes one by one,
or `done` to stop here.
U: improve
A: [silent: get_next_steps, pick implement_contact_info, scan project ->
found src/app/(auth)/signup/page.tsx]
A: Found `src/app/(auth)/signup/page.tsx:42`. I'd add this snippet for
+10% on this step:
```tsx
tlq('set', 'ContactInfo', { email, phone });
Apply? Reply yes / skip / show another.
U: yes
A: [silent: apply edit, verify_and_score (fresh idempotency_key),
get_next_steps, create_login_link]
A: Tracking is live. Tracklution score: 45/100. Top 2 ways to reach 100%:
improve to keep going, or done to stop here.
U: done
### Duplicate-account silent fallback
U: Install Tracklution.
A: Tracklution needs your email and website URL. Reply with both (e.g.,
you@example.com mysite.com). Type advanced to use OAuth instead.
U: bob@existing.com bobshop.com
A: [silent: POST /install/quick-setup → 409 duplicate_account →
next_action.tool === "oauth_fallback" → write tokenless .cursor/mcp.json]
A: Looks like you already have a Tracklution account. Enable the Tracklution
MCP and click Connect to sign in, then reply go.
U: go
A: [silent: get_status, list_containers -> bob's container for bobshop.com]
A: You're signed in. Add Tracklution to a NEW website, or connect to an
EXISTING container? Reply new <url> or existing.
U: existing
A: [silent: match bobshop.com, get_installation_scripts, apply,
verify_and_score -> ok, get_next_steps, create_login_link]
A: Tracking is live. Tracklution score: 78/100. Top 2 ways to reach 100%:
improve to walk through them one by one, or done to stop here.
### User chose `advanced` explicitly, then added a NEW website
U: Install Tracklution.
A: Tracklution needs your email and website URL. Reply with both (e.g.,
you@example.com mysite.com). Type advanced to use OAuth instead.
U: advanced
A: [silent: write tokenless .cursor/mcp.json]
A: I added a tokenless Tracklution MCP entry. Enable it in your editor and
click Connect to sign in, then reply go.
U: go
A: [silent: get_status, list_containers -> 1 container for othersite.com]
A: You're signed in. Add Tracklution to a NEW website, or connect to an
EXISTING container? Reply new <url> or existing.
U: new https://newsite.example.com
A: [silent: register_and_provision({auth_token, website_url, framework, agent_client, idempotency_key}),
get_installation_scripts, apply, verify_and_score -> only_pageview_seen,
get_next_steps, create_login_link]
A: Tracking is live. Tracklution score: 35/100. Top 3 ways to reach 100%:
improve to walk through the in-code changes, or done to stop.
### Multi-client ambiguous (advanced + new website + multi-company account)
U: Install Tracklution.
A: Tracklution needs your email and website URL. Reply with both (e.g.,
you@example.com mysite.com). Type advanced to use OAuth instead.
U: advanced
A: I added a tokenless Tracklution MCP entry. Enable it in your editor and
click Connect to sign in, then reply go.
U: go
A: [silent: get_status, list_containers -> 27 containers across 2 clients]
A: You're signed in. Add Tracklution to a NEW website, or connect to an
EXISTING container? Reply new <url> or existing.
U: new https://brand-new.example.com
A: [silent: register_and_provision -> HTTP 409 multi_client_ambiguous]
A: Multiple companies detected on this account. Open
https://app.tracklution.com and add the new container under the correct
company; then re-run with the resulting container_id.
## Magic install — one POST, one file write
The one HTTP request you make from inside the agent:
```http
POST https://api.trlution.com/install/quick-setup
Content-Type: application/json
{
"idempotency_key": "<fresh UUID-v7 or 16-128 chars [A-Za-z0-9_-]>",
"email": "<user email>",
"website_url": "<production URL>",
"framework": "html" | "nextjs",
"agent_client": "cursor" | "claude-code" | "codex" | "windsurf" | "cline"
}
Use api.trlution.com (short host) directly. api.tracklution.com
302-redirects here and that redirect silently drops POST bodies in several
HTTP clients (PowerShell Invoke-RestMethod, node fetch with
redirect: "manual", some agent host sandboxes).
The success response (HTTP 200) carries the handles you need:
{"status": "ok","data": {"mcp_token": "<long JWT>", // 90-day MCP transport token → host MCP config"mcp_token_expires_at": "<ISO-8601>","laravel_auth_token": "<short JWT>", // ~60-min user token → REST onboarding (below)"laravel_auth_token_expires_at": "<ISO-8601>","container": { "id": "...", "hash": "...", "website_domain": "...", "tracking_domain": "..." },"mcp_config_snippet": {"tracklution": {"url": "https://mcp.tracklution.com/mcp","headers": { "Authorization": "Bearer <mcp_token>" },},},"mcp_endpoint": "https://mcp.tracklution.com/mcp",},"next_action": {"tool": "merge_mcp_config","args": { "target_path": ".cursor/mcp.json", "merge_key": "mcpServers.tracklution" },"reason": "Merge data.mcp_config_snippet, then follow agent-install.md turn 3 hand-off.",},}
Save container.id AND container.hash to scratch state — every follow-up
onboarding-tool call needs both. Both tokens are secrets — use them in
headers only, never echo them to chat.
Idempotency rule (important): generate ONE idempotency_key for
quick-setup, persist it, and reuse it on any quick-setup retry — that
endpoint replays the SAME token, so a retry with a new key trips
409 duplicate_account. By contrast verify-and-score and login-link (below)
replay their cached response VERBATIM on key reuse, so send a FRESH
Idempotency-Key header for EACH of those calls or you'll get a stale result.
Turnkey path — npx tracklution install: instead of doing the POST + file
write + REST onboarding by hand, you can run one command that does all of it
deterministically (zero extra deps) and prints a single machine-readable line:
npx tracklution install --host=<claude-code|cursor|codex|windsurf|cline> \
--framework=<html|nextjs> --email=<email> --url=<production-url>
It provisions, writes the correct host MCP config (e.g. .mcp.json for Claude
Code, with type:"http" + the Bearer), injects the base loader for plain HTML,
emits framework snippets for YOU to apply, runs the day-0 baseline verify, and
prints { status, host, framework, container_id, config_path, restart_required, score, login_url, snippets, next_steps }. Neither token is printed. Apply any
returned framework snippets, then send the Turn 3 hand-off.
Per-host config file (the file you write data.mcp_config_snippet into):
| Host | File | Notes |
|---|---|---|
| Cursor | .cursor/mcp.json (project root) | Shallow-merge into mcpServers. 2-space indent. |
| Claude Code | .mcp.json (project root) | Shallow-merge into mcpServers. The server entry REQUIRES "type":"http" (the snippet omits it — add it). Restart Claude Code (or /mcp) after writing. claude mcp add is an OPTIONAL fallback only when the claude binary is on PATH. |
| Codex | ~/.codex/config.toml (POSIX) / %USERPROFILE%\.codex\config.toml (Windows) | TOML. Header table is http_headers NOT headers. Restart Codex after writing — no hot-reload. |
| Windsurf | ~/.codeium/windsurf/mcp_config.json | Accepts url or serverUrl. Full restart after write — no hot-reload. |
| Cline | platform-specific cline_mcp_settings.json (see reference doc) | type: "streamableHttp" required. |
Error handling — match on next_action.tool first, then errors[0].code:
next_action.tool === "oauth_fallback" (HTTP 409 duplicate_account) →
silent OAuth fallback. Write tokenless config. Send Turn 3 duplicate
hand-off. Do NOT explain the error.errors[0].code === "validation_failed" (HTTP 422) → re-prompt for the bad
field once. Most common: website_url is a localhost / IP literal.errors[0].code === "rate_limited" (HTTP 429) → respect
errors[0].details.retry_after_seconds. Tell user: "Rate-limited; try
again in N seconds."For the full error code table, see
agent-install-reference.md.
The MCP transport may not be live until the user restarts the host. You don't
have to wait: quick-setup also returns data.laravel_auth_token (a
short-lived ~60-min user JWT), which authenticates the SAME onboarding
endpoints the MCP tools call. Use it as Authorization: Bearer <laravel_auth_token> (NEVER print it). {container} below is
data.container.hash (the trc_… value). Base host: api.trlution.com.
Sequence (each step optional except verify):
GET /mcp-api/v1/onboarding/containers/{container}/installation-scripts?framework=html|nextjs
→ returns the base loader + framework event snippets. YOU apply the snippets
to the user's code (the agent owns code edits; the API only emits them).POST /mcp-api/v1/onboarding/containers/{container}/verify-and-score with a
fresh Idempotency-Key header → returns a day-0 configuration baseline
score (NOT proof that live events are flowing — that needs real traffic).GET /mcp-api/v1/onboarding/containers/{container}/next-steps → human-readable
next actions for the Turn 5 hand-off.POST /mcp-api/v1/onboarding/containers/{container}/login-link with a
fresh Idempotency-Key header and body { "target_page": "dashboard" }
→ returns the single dashboard URL you ARE allowed to show the user.verify-and-score and login-link replay their cached body VERBATIM per
idempotency key, so send a NEW key for every call (reusing a key returns the
stale earlier result). installation-scripts and next-steps are plain GETs —
no key needed. (npx tracklution install does this whole sequence for you.)
Post-restart re-verify (fresh session): after the user restarts and the MCP
connects, a brand-new agent session has lost container.{id,hash} and the
laravel_auth_token has likely expired. Recover context by calling the MCP
list_containers tool, then re-run verify/next-steps through the MCP tools
(which mint their own auth) — do NOT try to reuse the expired REST token.
Write the tokenless MCP entry (same body as the magic snippet, but omit the
headers block). The host's UI then surfaces a Connect button (Cursor) or
its equivalent. User clicks it, completes browser OAuth, and reports back
with go. On go, run Turn 4 with the OAuth path of Step 2 — ask the
"new vs existing" branch question, then call list_containers (or
register_and_provision({auth_token, ...}) for the new branch), then
continue with Step 3.
If list_containers returns 0 containers, skip the branch question and go
straight to the new <url> path with auth_token + the website URL the
user supplied originally (or ask once for the URL if you don't have it).
Brand-new + advanced is fully supported — the server reads identity from
the JWT, so name / email arguments are NOT required.
If host detection fails, neither path completes, or any failure mode lands outside the recovery branches above, send once and stop:
Drop this into Cursor, Claude Code, Codex, Windsurf, Cline, Lovable, Replit, or Bolt. The agent reads our install protocol, mounts the Tracklution MCP, and finishes the setup.
Install Tracklution to this siteInstall Tracklution tracking — see https://www.tracklution.com/agent-install/The agent writes this into .cursor/mcp.json:
{
"mcpServers": {
"tracklution": {
"url": "https://mcp.tracklution.com/mcp"
}
}
}Server Side Tracking
Google Ads
Meta
TikTok Server Side Tracking
Shopify Server Side Tracking
GA4 Server Side Tracking
LinkedIn Server Side Tracking
Snapchat Server Side Tracking
WooCommerce Server Side Tracking
WordPress Server Side Tracking
Pinterest Conversions API
Microsoft (Bing) Server Side Tracking
Stripe Conversion Tracking
(For Agents) Automatic MCP installation
Server-Side Tracking, First-Party Cookies and Conversion APIs for any website with easy installation. Simple yet powerful tracking tool for digital advertising.


4.8+ Rating on G2 and Trustpilot
Helsinki
Simonkatu 6 A
00100 Helsinki, Finland
New York
307 W 38th St
NY 11105, United States



For AI coding agents: read www.tracklution.com/agent-install.md for one-shot install, or tell your agent: “Install Tracklution.”
© Tracklution Oy 2026. All rights reserved.
GTM template with instructions video from Simo Ahava!