Add analytics with Cursor
undefined
To add analytics with Cursor, open the project, start the agent and paste the prompt below. Cursor's agent runs the curl calls itself, so it can get an AgentFirstStack key, create the site, serve the tracker from your own domain through a small proxy, add it to your root layout and check the live site without you opening a dashboard. Two Cursor defaults change how that goes: the agent's file tools can't see .env, and sandboxed commands can't reach the network until you allow it. Both are covered below. Other tools and platforms are in add analytics with an AI agent.
The prompt
Add analytics to this project with AgentFirstStack. It's free, open-source analytics built for agents, and you can do all of it yourself: there is no signup form, and no email or verification is needed. 1. Read https://agentfirststack.com/llms.txt and https://analytics.agentfirststack.com/llms.txt. 2. Cursor hides .env from your file tools, so check it from the terminal. If it already has AGENTFIRSTSTACK_API_KEY, use it and read AGENTFIRSTSTACK.md. Otherwise get a key with one request: curl -X POST https://agentfirststack.com/v1/signup Append api_key to .env as AGENTFIRSTSTACK_API_KEY from the terminal, make sure .env is in .gitignore, and add it to the production environment's secrets (or tell me where). Name the project after the domain: PATCH https://agentfirststack.com/v1/me. 3. Create a site for the production domain and read GET /v1/sites/:id/install?framework=... for this project's framework. Serve the tracker from the site's own domain with the first-party proxy that fits this project's host (Next.js proxy.ts, a Cloudflare Worker route, a Netlify Edge Function, vercel.json or nginx). Keep first_party_proxy.proxy_key in a server-only env var (AFS_PROXY_KEY), never in page code. Then put the proxied snippet (/_a/s.js) in the <head> of the root layout. Only if the host can't proxy, use the direct snippet and note in AGENTFIRSTSTACK.md that ad blockers block it. 4. Create goals for sign-ups, purchases and the main buttons. Send conversions only the server knows about (a paid order, a verified account) as server events. 5. Add an email destination, a weekly report, and alerts for a traffic drop and for no data. 6. Deploy (or tell me to), open the site once, then run verify and fix what it reports. 7. Write the site id and the env var names (never the values) in AGENTFIRSTSTACK.md, add the AgentFirstStack block from the manual to AGENTS.md, and create a claim link for me with POST https://agentfirststack.com/v1/claim-link. 8. Run GET https://agentfirststack.com/v1/setup?services=analytics and work through its next_steps until it says "ready": true. When you're done, tell me what you set up, how you verified it, and give me the claim link.
Use the agent, not Ask mode: Ask mode doesn't edit files or run commands.
Let the agent reach the API
Every step is an HTTPS call to agentfirststack.com or analytics.agentfirststack.com. How Cursor treats those calls depends on its run mode (Settings > Agents > Approvals & Execution): Auto-review, Allowlist or Run Everything. Cursor's sandbox blocks network access by default and opens only what your network mode and sandbox.json allow; the default allowance covers package managers, not arbitrary APIs. A command that needs network outside the sandbox goes to the reviewer or to you for approval.
So you'll either approve the first few curl calls, or allow the two hosts for this project in .cursor/sandbox.json:
{
"networkPolicy": {
"allow": ["*.agentfirststack.com"]
}
}
In Cursor's pattern syntax, *.agentfirststack.com matches the subdomains and agentfirststack.com itself.
The key and .env
Cursor ignores .env* files by default, on top of whatever is in .gitignore, so the agent can't open or edit .env with its file tools. That's a good default for a secret. The ignore rules don't apply to terminal commands, though, so the agent reads and appends to .env from the terminal. That's why the prompt says so; without the hint, some runs conclude there's no key and sign up again.
The key never belongs in browser code. The tracker snippet only carries the site id (data-site="site_..."), which is public. The key is for server code and for the agent's own calls: goals, verify, server events, crawler reports. The proxy key is server-only too. In a Next.js app that means no NEXT_PUBLIC_ prefix on either; in Vite, no VITE_ prefix.
Add the MCP server
With the MCP server, the agent calls tools like analytics_get_stats and afs_check_setup instead of composing curl commands, and you can ask "where did sign-ups come from this week?" in chat. Cursor reads remote servers from .cursor/mcp.json (this project) or ~/.cursor/mcp.json (every project), and expands ${env:NAME} in the URL and headers:
{
"mcpServers": {
"afs": {
"url": "https://agentfirststack.com/mcp",
"headers": { "Authorization": "Bearer ${env:AGENTFIRSTSTACK_API_KEY}" }
}
}
}
That file names the variable, not the key, so it's safe to commit. The catch: for remote servers Cursor doesn't read envFile, so the variable has to come from your shell profile or system environment, not from the project's .env. Export it in ~/.zshrc (or your shell's equivalent) and restart Cursor.
No key at hand? Leave out headers. AgentFirstStack's MCP server supports OAuth 2.1 sign-in, and Cursor runs the authorization code flow with PKCE: you sign in with Google, pick a project (or create one) and choose full or read-only access. OAuth tokens can do everything except create API keys or claim links, which you don't need once you're signed in.
Where the proxy and the snippet go
Ad blockers block requests to analytics.agentfirststack.com, so the prompt has Cursor serve the tracker from your own domain: a small proxy forwards /_a/* to AgentFirstStack, and the page loads /_a/s.js. GET /v1/sites/:id/install returns the proxy code (first_party_proxy) for a Cloudflare Worker route, Next.js, vercel.json, netlify.toml and nginx, plus framework code for html, nextjs, astro, react and wordpress. Each proxy sends the site's x-afs-proxy-key, a secret that belongs in a server-side env var such as AFS_PROXY_KEY; without it every visitor looks like the proxy's one address.
| Project | Proxy | Snippet |
|---|---|---|
| Next.js | proxy.ts (middleware.ts before 16) | <script async> in app/layout.tsx; see the Next.js guide |
| Vite, React, Vue, Svelte SPA | The host: Cloudflare Worker route, Netlify Edge Function, vercel.json | index.html; route changes are tracked through the History API |
| Astro | An on-demand endpoint, or the host | src/layouts/Layout.astro with is:inline; see the Astro guide |
| WordPress | Cloudflare Worker, nginx, or a must-use plugin | A wp_head hook; see the WordPress guide |
| Shopify, Webflow | Not possible on their hosting | The direct snippet; ad blockers block it (Shopify, Webflow) |
Before deploying, make sure AFS_PROXY_KEY is set in the production environment too. A proxy without it still forwards events, and verify then reports proxy_key.
Keep later sessions in the loop
The prompt ends by adding a short AgentFirstStack block to AGENTS.md. Cursor reads AGENTS.md in the project root, so later agent sessions know analytics exists, where the ids are, and to run the setup check before they touch tracking. If you keep project rules in .cursor/rules instead, remember they must be .mdc files; Cursor ignores a plain .md there.
Cloud agents have internet access by default. Add AGENTFIRSTSTACK_API_KEY as a secret in the cloud agent settings and it reaches the agent as an environment variable; a Build Secret doesn't reach the running agent. The snippet only goes live once the agent's branch is merged and deployed, so run verify and the setup check after that deploy, from a local session or a follow-up run.
Check it worked
After the deploy, the agent runs three checks, and you can run them yourself:
K=$AGENTFIRSTSTACK_API_KEY
# 1. the snippet, the script, your CSP and whether events arrived, with fixes
curl -s -X POST https://analytics.agentfirststack.com/v1/sites/$SITE/verify -H "Authorization: Bearer $K"
# 2. everything an analytics setup should have, until "ready": true
curl -s "https://agentfirststack.com/v1/setup?services=analytics" -H "Authorization: Bearer $K"
# 3. numbers
curl -s "https://analytics.agentfirststack.com/v1/sites/$SITE/stats?period=today" -H "Authorization: Bearer $K"
Verify fetches /_a/s.js through your proxy to check it serves the tracker, and only counts events from a real browser: open the production URL yourself once, or have a headless browser open it with ?afsa_debug=1, which keeps the visit as test traffic out of your reports. Events from localhost and preview hosts are dropped on purpose, because a site accepts events only from its own domain and subdomains.
FAQ
Why does the agent keep asking to run curl?
Cursor's sandbox blocks network access to hosts that aren't allowed. Approve the calls, or add *.agentfirststack.com to networkPolicy.allow in .cursor/sandbox.json.
The agent says there's no .env. Is the key lost?
Probably not. Cursor hides .env* files from the agent's file tools by default. Ask it to check with a terminal command such as grep AGENTFIRSTSTACK_API_KEY .env. If the key really is gone, a person who claimed the project can make a new one in the dashboard.
Do I have to use MCP?
No. The setup works with curl alone. MCP is for afterwards, when you want to ask about traffic in chat without the agent writing requests.
Can Cursor's MCP config read the key from the project's .env?
Not for a remote server. Cursor expands ${env:NAME} from your shell profile or system environment. Export the variable there, or use OAuth and skip the key.
Does the tracker use cookies?
No. By default a visitor is a hash of a daily salt, the site, the IP address and the user agent. Nothing is stored in the browser unless you switch the site to persistent mode, which keeps a random id in localStorage.
Related
- AnalyticsAdd analytics with an AI agentThe prompt, the checks, and every tool and platform.
- AnalyticsAdd analytics with Claude CodeOne prompt in the terminal, then questions over MCP.
- AnalyticsAdd analytics with OpenAI CodexCLI, IDE or cloud, with network access sorted.
- AnalyticsAdd analytics with WindsurfCascade, mcp_config.json and the setup check.
- AnalyticsNext.js analytics in one promptApp Router, Pages Router, proxy.ts and Vercel.
- AnalyticsAstro analytics in one promptLayouts, is:inline and the ClientRouter.
- All servicesOne MCP server for every serviceAnalytics, tags, mail and replay tools on one key.
- AnalyticsGoogle Analytics MCP comparedRead GA4, or let the agent create the analytics.