---
name: whoisbrowsing
description: Add whoisbrowsing (live visitor view) to a website project with no sign-up. Create a site with one API call, put one script tag in the file every page shares, verify it, and hand the human a watch link and a claim link. Use when asked to add whoisbrowsing, live visitors, or a way to see who is on the site right now.
metadata:
  author: Sandeep Arneja LLC
  version: 1.0.0
---

# Add whoisbrowsing to a project

Source: https://whoisbrowsing.com/SKILL.md. Follow these steps in order. The human asking you to add whoisbrowsing is your go-ahead to create one site and edit one file (plus one line in AGENTS.md or CLAUDE.md): say in one line what you will do, then do it.

> **If the human gave you a tag (a `<script ... data-site="...">` line), the site already exists.** Do not call the API or `create_site`, and skip "Hand the human two links" and the AGENTS.md line. Put that tag in as under "Put the tag in", check the diff (Verify step 1), run the page and confirm the tag is in the served HTML (step 2), and tell the human to open the site's page on whoisbrowsing.com, which they already have, to see it connect. Skip `check_live`: you have no owner key. If the dev server's host is not one of the site's domains, say so instead of creating a site.

## What it is

whoisbrowsing shows a site's owner who is on the website right now: every current visitor's cursor drawn live on the owner's own page, plus the page they are on, where they came from (Google, ChatGPT and others), an approximate city and their device. It is one script tag, under 4 KB gzipped, loaded with `defer`, and it never changes how the page looks. Free, no cookies on visitors, and nothing about visitors stored. There is no package to install and no build step.

The whole job:

1. Create a site (one API call, no account).
2. Put its tag on every page.
3. Hand the human two links: watch and claim.
4. Verify.

## Create a site

Pick the domains first: every website the tag will run on.

- The dev server's host and port, from the project's dev script or framework config. Next.js and Nuxt default to `localhost:3000`, Vite-based apps to `localhost:5173`, Astro to `localhost:4321`, Angular to `localhost:4200`.
- The production domain, if the project names one (in its deploy config or README, for example).

Each website is separate: localhost and production never mix, `www.` is the same website as the bare domain, and `localhost:3000` is not `127.0.0.1:3000`. One site holds up to 20 domains, so create **one site per project**.

```bash
curl -sS -X POST https://whoisbrowsing.com/api/agent/sites \
  -H 'Content-Type: application/json' \
  -d '{"domains":["localhost:3000","example.com"]}'
```

Add `"name":"My app"` to the body for a label; it is optional and defaults to the first domain. No auth, no account.

The answer is `201` with JSON like this:

```json
{
  "siteId": "a1b2c3d4e5f6",
  "snippet": "<script src=\"https://live.whoisbrowsing.com/s.js\" data-site=\"a1b2c3d4e5f6\" defer></script>",
  "watchUrls": {
    "localhost:3000": "http://localhost:3000/#wib=<owner key>",
    "example.com": "https://example.com/#wib=<owner key>"
  },
  "claimUrl": "https://whoisbrowsing.com/claim?t=<one-time token>",
  "installDocs": "https://whoisbrowsing.com/install",
  "next": ["Put the snippet on every page, unchanged: ...", "..."]
}
```

- `snippet`: the tag for every page, unchanged. Its site ID is public and fine to commit.
- `watchUrls`: one watch link per website. Private, see below.
- `claimUrl`: the one-time claim link. Private, see below.
- `next`: these steps again, filled in for this site.

Errors are JSON too, each with a `hint` that says how to fix the request:

| Status | `error` | What to do |
|---|---|---|
| 400 | `invalid_json`, `invalid_body` or `invalid_domains` | Fix the body as the hint says, then send it again |
| 429 | `rate_limited` | Do not retry in a loop. With `reason: "ip"`, 10 sites were created from this network in the last hour: wait `retryAfterSec` seconds (also sent as `Retry-After`). With `reason: "cookie"`, this client holds 5 unclaimed sites: reuse one, or have the human claim them |
| 500 | `internal_error` | Try again in a minute |

The spec: https://whoisbrowsing.com/openapi.json. With the MCP server connected (https://whoisbrowsing.com/mcp), the `create_site` tool does the same thing and gives the same answer.

## Put the tag in

Put the snippet in the one file every page shares, so it loads on every page, and change nothing else. Work out the framework from the project's files (`package.json`, config files), then follow its guide: each one is Markdown with the exact code for that platform.

| Platform | Where the tag goes | Guide |
|---|---|---|
| Next.js (App Router) | `app/layout.tsx`, as a `next/script` tag with `strategy="afterInteractive"` and `data-site` | [nextjs.md](https://whoisbrowsing.com/install/nextjs.md) |
| React (Vite) | The `<head>` of `index.html` in the project root | [react.md](https://whoisbrowsing.com/install/react.md) |
| Vue | The `<head>` of `index.html` in the project root | [vue.md](https://whoisbrowsing.com/install/vue.md) |
| SvelteKit | `src/app.html`, the template every route renders into | [svelte.md](https://whoisbrowsing.com/install/svelte.md) |
| Astro | The `<head>` of the shared layout, usually `src/layouts/Layout.astro` | [astro.md](https://whoisbrowsing.com/install/astro.md) |
| Remix | The `<head>` of the `Layout` component in `app/root.tsx` | [remix.md](https://whoisbrowsing.com/install/remix.md) |
| Nuxt | A `script` entry in `app.head` in `nuxt.config.ts` | [nuxt.md](https://whoisbrowsing.com/install/nuxt.md) |
| Angular | The `<head>` of `src/index.html` | [angular.md](https://whoisbrowsing.com/install/angular.md) |
| Plain HTML | Before `</body>` on every page, or in `<head>` (the tag has `defer`) | [html.md](https://whoisbrowsing.com/install/html.md) |
| WordPress | The theme, or an "insert headers and footers" plugin | [wordpress.md](https://whoisbrowsing.com/install/wordpress.md) |
| Shopify | `layout/theme.liquid`, before `</body>` | [shopify.md](https://whoisbrowsing.com/install/shopify.md) |
| Webflow | Site settings, Custom code, Footer code | [webflow.md](https://whoisbrowsing.com/install/webflow.md) |
| Squarespace | Code Injection, Footer | [squarespace.md](https://whoisbrowsing.com/install/squarespace.md) |
| Wix | Settings, Custom Code, all pages, end of body | [wix.md](https://whoisbrowsing.com/install/wix.md) |
| Ghost | Settings, Code injection, Site footer | [ghost.md](https://whoisbrowsing.com/install/ghost.md) |
| Framer | Site Settings, Custom Code, end of body | [framer.md](https://whoisbrowsing.com/install/framer.md) |
| Your own agent's MCP setup | Claude Code, Cursor and Codex | [ai-agent.md](https://whoisbrowsing.com/install/ai-agent.md) |

Any other framework: put the tag in the HTML template every page is rendered into. A hosted site builder (WordPress, Shopify, Webflow, Squarespace, Wix, Ghost, Framer) often leaves you no project to edit: give the human the snippet and that guide's steps instead. With the MCP server, `get_install_instructions` returns these guides.

**Content-Security-Policy.** If the site sends a CSP (look in the framework config, the middleware and the hosting headers), add `script-src https://live.whoisbrowsing.com` and `connect-src wss://live.whoisbrowsing.com` to it. Most sites send none.

## Verify

Do not report success from the diff alone.

1. Check the diff: one tag with this site's `data-site`, in the shared file, and nothing else changed.
2. Run the dev server (or deploy), so a page with the tag is served at one of the site's domains.
3. Ask the human to open the watch link for that website, then to open the site in a Chrome Incognito or Safari private window. They should see their own cursor arrive on the page. Their normal browser is never counted as a visitor once they've opened the watch link in that browser, which is why the private window matters.
4. From your side: with the MCP server connected, call `check_live({siteId, key})` while a page with the tag is open. `key` is the owner key: the part after `#wib=` in the watch link. Never write it into a file. It says whether the script is connected right now, on which websites, and whether the owner is watching. If you can run a browser, load the page in a fresh private context and call `check_live` while that page is open.

If nothing shows, look for the tag in the page source, check that the address matches one of the site's domains (port included), check the CSP, and try without an ad blocker. Visitors from the EU/EEA, UK and Switzerland, and browsers with Global Privacy Control, are never shown, so a test from there shows nothing.

## Hand the human two links

Put both links in your reply to the human right away, and say what each one does:

- **The watch link** (`watchUrls["<website>"]`, one per website): "Open this to watch your visitors live on your own site. After the first time, just open your site." It holds a forever owner key in its `#wib=` fragment, and the key keeps working after the site is claimed. **Treat the watch link like a password.**
- **The claim link** (`claimUrl`): "Open this and sign in with Google to keep this site in your account." It works once and expires after 30 days, so hand it over now. Until it is claimed, the site works but sits in no account, and the human has no dashboard for it.

Never write either link into a file, a commit, AGENTS.md, CLAUDE.md, a README, an issue or a log. The snippet is the only part of the answer that goes into the code.

## Add one line to AGENTS.md or CLAUDE.md

If the project has an `AGENTS.md` or a `CLAUDE.md`, add this line to it (to both, if both exist), with the file you edited in place of `<file>`:

```
This project uses whoisbrowsing (live visitor view). Script tag in <file>. Docs: https://whoisbrowsing.com/SKILL.md
```

Do not create either file just for this line. The line holds no watch link, claim link or key.

## With the MCP server

Instead of calling the API, an agent can connect to the remote MCP server at https://whoisbrowsing.com/mcp (streamable HTTP, no auth). In Claude Code:

```bash
claude mcp add --transport http whoisbrowsing https://whoisbrowsing.com/mcp
```

Its tools: `create_site({domains, name?})`, the same as the API; `get_install_instructions({platform})`, the guides above; and `check_live({siteId, key})`, where `key` is the part after `#wib=` in the watch link. Cursor and Codex setup: https://whoisbrowsing.com/for-agents.md

## Privacy

The privacy promise, word for word, for when the human asks:

- Your visitors' browsers send the page, pointer position, clicks, scroll, device type, source, browser and operating system, and time on site. Never keystrokes, form values or page text.
- Nothing about your visitors is stored on our servers.
- No cookies on your visitors.
- Visitors from the EU/EEA, UK and Switzerland, and browsers with Global Privacy Control, are never shown.

Details, and a paragraph the site can paste into its own privacy policy: https://whoisbrowsing.com/privacy

## Never

- Never call whoisbrowsing "open source".
- Never say it records sessions, makes replays or heatmaps, or keeps history or analytics reports. It is live only.
- Never say it captures typing or keystrokes, or identifies visitors. It shows an approximate city, never an identity.
- Never promise that it makes the site GDPR compliant. Say what it does (the Privacy section above); this is not legal advice.
- Never write the watch link, the claim link or an owner key into a file, a commit or a log.
- Never call the API in a loop, or create a site per page, per file or per retry. One site per project; it holds several domains.
- Never change anything else to add it: no package, no build step, no edits to unrelated files.
