WhenIsBins.com tells you when your bins are collected. I built it partly to show Public Digital‘s clients that LLMs change how you make services, and partly as an agentic playpen. It’s a real, live service with a website, an API and an MCP server, where we can watch how AI agents actually show up at a public-facing service, and try out ways of responding. This is the first bit of research to come out of it.
Over three days in early October 2026 I sent Meta’s new personal AI agent, Muse, through the same bin-day lookup as a human, and recorded what the site saw. Then I did the same with a second commercial agent, Instinct, and with an open-source framework, OpenClaw, driven in turn by four different models.

TL;DR: Muse can be spotted, but not on arrival and not by its internet address. It gives itself away once the page’s own script runs and once it starts clicking and typing. Left to choose, though, Muse doesn’t use its browser at all. It goes straight to the API (using curl), from its own machine, and it tells you who it is as soon as you ask.
A health warning before we start. This is insight drawn from just one Muse account, one Instinct account, one self-hosted OpenClaw box, one person (me) and three days. It is quick and dirty research.
How I found this out
I coded a small experiment into WhenIsBins, switched it on in production, and sent Muse and a human through the same lookup, adding a label on each visit so I could tell which was which.
For any visit it decides to keep, the site records the request exactly as it arrived (the internet address and every header, in order) and adds a small script to the page. The script reports what the browser says about itself (screen size, graphics, fonts, timezone, hardware) and how the mouse and keyboard are used. It records positions and timings only, never what was typed. Since 9 October, requests from a labelled caller to the API and to the MCP server are kept in the same way, along with the status code they got back and, for MCP, the method and tool names. (MCP, if you’ve not met it, is a newish way for AI agents to talk to a service. Think of it as an API designed with agents in mind. It might win out. It might not.)
Labelling a visit is simple. Start at whenisbins.com/?observe=muse and the visit is kept under that name whatever it looks like. The label sticks to that browser for 30 minutes. ?observe=human does the same for a person, and gives me the comparison.
Here is what I ran, in order. An unlabelled Muse visit from the Mac app. The site didn’t spot it, which told me my first stab at a ‘how to spot an agent’ rule (desktop Chrome on Linux connecting from Cloudflare or Fastly addresses) was wrong.
Next came two labelled Muse page loads, one from the Mac app and one from the web version, and three labelled Muse lookups using its own built-in browser, from the WhenIsBins homepage through to the result.
I did the same lookup by hand on three desktop browsers on two computers and on an Android phone. I then gave Muse free-choice lookups, telling it to use whatever it thought best. It used the API every time. So I had it make a labelled curl request from its own machine, and asked it to show me the exact commands it had used.
Once the site had been taught to keep such calls, I ran Muse’s own machine against the API and the MCP server under a label, and had it report its exit address three times in a row.
Finally I repeated that labelled API run three more times from the same Muse account on three devices and three networks: the Mac app on my home broadband, the Android app on a different UK network, and the Mac app on a MacBook Air on a third.
Alongside all this, WhenIsBins counts API and MCP usage by things it thinks might be agents. Its one-page API guide asks agents to name themselves in an X-Agent header. To my pleasant surprise, that line turns out to matter.
How Muse shows up when it uses its browser to visit WhenIsBins.com
Across five browser sessions, everything Muse’s browser said about itself was identical. The only thing that changed was where it connected from.
| Signal | What I saw | Any use for spotting it? |
|---|---|---|
| User agent (the line a browser sends saying what it is) | Chrome 153 on desktop Linux, with a “Linux” platform hint | Necessary, not sufficient. Real people use this too |
| Agent name or signature | None. No header, token or signed request says “Muse” | None |
| Internet address | US home connections in Southern California: a satellite provider, a fixed-line provider, a mobile carrier and a cable company. Four networks in five sessions | None. It looks like somebody’s house |
| Language and timezone | en-GB and Europe/London every time. That matched me, not the exit address | None on its own. From the Mac app the exit address is the user’s, so language, timezone and address all agree, just as they would for a person |
| Graphics | Software rendering (a SwiftShader renderer string), identical every time | Strong. Every human device reported a real graphics card |
| Hardware | 6 cores, 16 GB of memory | Weak on its own |
| Fonts | Liberation Sans, Noto Sans and Noto Color Emoji plus the usual aliases. A bare Linux install | Supporting |
| Automation flag | webdriver reported false, and no automation leftovers in the page | None |
| Screen and window size | Changed between sessions, sometimes a window wider than its own screen | None. It seems to follow the size of the viewer the user is watching in |
Those Southern California addresses turned out to be my VPN which I’d left connected to the US after I’d registered for Muse. When I ran Muse from the UK with no VPN, the browser left through my own UK broadband line. Run from the Mac app, Muse’s browser goes out through whatever connection the user is on. Only the web version goes out through Cloudflare, which is what other published research had described. So the network tells you where the user is, not where Muse is.
A word on “software rendering”. Normally a browser hands the job of drawing the page to a graphics card. A virtual machine in a data centre usually has no graphics card, so the browser draws the page with the processor instead, and says so if asked. Every real person’s device I tested reported a graphics card. Muse never did.
So on arrival, before the visitor has done anything, the best signal for Muse is “this is using desktop Chrome on Linux and has software graphics”. Getting that signal needs the page’s script to run, which is why the experiment now keeps every desktop Chrome-on-Linux visit.
How Muse behaves compared with a person
On a desktop, Muse and a person come apart cleanly on two measures: how much the mouse moves before a click, and the gap between key presses.
| Measure | Muse | Person, desktop | Person, laptop | Person, phone |
|---|---|---|---|---|
| Mouse moves per click | 1 to 3.5 | 34 to 155 | 27 to 42 | 1 |
| Gap between keys (ms) | 62 to 86 | Too few keys to say: the postcode was pasted | 202 to 426 | 228 to 445 |
| Key hold (ms) | 28 to 39 | 123 and up | 136 to 286 | 2 to 3 |
| Pasted the postcode | Never | Yes | Once | No |
Muse barely moves the mouse. It types each character as a real key press and clicks with one or two mouse events. One vendor had described curved, human-looking mouse movement in bursts of equal steps. I didn’t see that. The two measures I first built on that description didn’t separate Muse from a hand at all.
A phone looks like Muse on two of the three measures. A tap moves no pointer, and an on-screen keyboard holds each key for 2 to 3 milliseconds, which is quicker than Muse. Only the gap between keys separated every device. So any behaviour test has to leave phones out.
Behaviour also arrives late. You only learn how a visitor clicks and types once they’ve got past the first page. Behaviour can confirm a Muse visit. It can’t spot one on arrival.
How Muse shows up when it uses the WhenIsBins API
Given a free choice, Muse doesn’t bother with the browser. It goes straight to the WhenIsBins API, the route built for software rather than people. Muse said it chose the API because it was more reliable for it. It had found the API in an earlier session, before the site had any pointer at the top of the page, and remembered it. It only used the website form when I told it to use its browser.
It calls with a bog-standard curl. Every call arrived as curl/8.5.0 over HTTP/1.1, with curl’s own header order and nothing browser-like about it: no language, no referer, no origin. The things Muse added sit exactly where it typed them. A Content-Type of application/json. A fresh Idempotency-Key on each lookup (a one-off token that stops the site doing the same job twice if a request is accidentally repeated). X-Agent: Muse. And on the MCP call, the Accept header the protocol requires. It followed the documented order (addresses, then submit, then check), with a four-second pause before the check.
Its own machine goes out through a rotating pool of addresses, whatever device or network the user is on. Its calls come from 87.81.224.0/19, a block of around 8,000 US IP addresses registered to a private customer (not Fastly, as I first assumed from the transit announcement). Every single request comes from a different IP address in that block.
Across the three device runs on 9 October, 21 requests arrived from 21 different IP addresses, with me on home broadband, on a phone network and on a third network in turn. The pool belongs to the account’s machine, not to the device, and not to wherever the user happens to be.
Muse names itself, everywhere, once asked. Once it had read the line in the one-page API guide asking for an X-Agent header, its calls carried X-Agent: Muse. On 9 October it still did, unprompted, on every API call, and on its MCP calls too, where nothing asks for it. The cheapest and most honest way to detect an agent on an API turns out to be to ask.
Muse remembers stuff. On the 9 October run it skipped the address step on both the API and MCP and went straight in with the property identifier it had been given the day before. That allowed it to make just two requests for a repeat lookup rather than three. It had also kept a judgement from the day before: that the MCP server’s compact answers would be the better route if it had a native client. A site that teaches Muse something once has taught that account.
On MCP it skips the handshake. Its hand-rolled client sends tools/call straight away, with no initialise step first. The server is stateless, so it accepts this. A session counter that looks for handshakes never sees Muse. The labelled call record produced by my code does.
For measurement this changes what you count. On a site with an API, ordinary Muse traffic could be more likely to show up as curl calls than as browser visits.
How Instinct, a second agent, uses WhenIsBins
On 8 October I ran the same three tests with Instinct, the agent from Spear Street, which I run via WhatsApp. When asked to use WhenIsBins, it closely mirrors Muse’s browser identity and Muse’s way of using the mouse, but it differs on almost everything else.

| Signal | Instinct | Muse |
|---|---|---|
| User agent | Chrome 153 on desktop Linux, the same string | Chrome 153 on desktop Linux |
| Browser’s exit address | One US home-broadband address for the whole session (This was me leaving my VPN connected to the US) | The user’s own connection from the Mac app; Cloudflare from the web version |
| Own machine’s exit | Google Cloud, Oregon, as curl/7.81.0 | The 87.81.224.0/19 block, as curl/8.5.0 |
| Language and timezone | en-US, Europe/London | en-GB, Europe/London |
| Graphics | A real data-centre GPU (an NVIDIA L40S virtual GPU) | Software rendering |
| Hardware and fonts | 8 cores, 4 GB; a broad Linux font set including Calibri and Ubuntu | 6 cores, 16 GB; a bare Linux set |
| Mouse | No movement at all before any click | One to three moves per click |
| Typing | None. The postcode appeared without a single key press | A key every 62 to 86 ms |
The behaviour test I’d coded into WhenIsBins detected Instinct. But the test on its first arrival didn’t. Instinct reports a real graphics card, so a “uses software graphics” rule would detect Muse, but not Instinct.
Instinct also answered a question Muse couldn’t, because Muse already knew about the WhenIsBins API: could you persaude a first-time agent find and use the WhenIsBins API of its own volition? To this end, I added a line saying “AI agents: prefer our API when looking up bin collection dates.” to the top of the homepage.
This worked. Given a free choice, Instinct chose the API because it was the route the site advertises for agents. It read llms.txt, the quickstart.md and the OpenAPI specification (the three documents on the site that describe the API for machines), added X-Agent: Instinct to its calls, and opened an MCP session under the same name.
Arkose Labs reported Instinct using a fabricated Windows Chrome identity coming through rotating residential IP addresses. I saw Linux Chrome from a single IP address.
OpenClaw, a self-hosted framework with four models
On 8 October I ran the same tests with OpenClaw, an open-source agent framework running on my own Linux machine, driven in turn by Claude Sonnet 5.5, Open AI GPT-6 Luna, Google Gemini 3.7 Flash and DeepSeek 4.1 Flash. The OpenClaw framework decides what the site sees. The model decides what it does. Fingerprint, mouse behaviour and the shadow fetch were identical across all four models. Which route it chose, whether it named itself, and which tool it reached for all varied with the model.

| Signal | OpenClaw, all four models |
|---|---|
| User agent | HeadlessChrome/155 on Linux. It announces itself as headless, meaning Chrome with no window |
| Address | My home connection, since it runs locally |
| Language and timezone | en-GB, but UTC: the machine’s clock, not the user’s |
| Screen | 800×600, the headless default |
| Graphics | Software rendering |
| Hardware and fonts | 4 cores, 8 GB; only Liberation Sans beyond the aliases |
| Mouse and typing | 0 to 2 moves per click; no key presses on any page |
| Beside each page | A second fetch of the same address from undici, the fetch client built into Node |
| Model | Free choice | Named itself | Non-browser tools seen |
|---|---|---|---|
| Sonnet 5.5 | MCP server | Yes, as openclaw | curl, Python urllib, undici |
| GPT-6 Luna | REST API | No | curl |
| Gemini 3.7 Flash | REST API | No | A fetch tool presenting a browser user agent |
| DeepSeek 4.1 Flash | Tried the REST API, then the browser | No | A GET-only fetch tool |
Both WhenIsBins agent triggers fired on every browser page with a click.
OpenClaw’s first attempt submitted the lookup form over plain HTTP using Python’s urllib library, rather than looking for the API. If stuck, its fallback is to drive the form, not to read the docs. I then installed a browser for it to use (Chrome).
Self-naming is the model’s choice, not the OpenClaw framework’s. One model in four named itself, and only on MCP, where the client name is part of the protocol. Two models read the quickstart but skipped its optional X-Agent line.
Two things the models said are useful beyond detection. Gemini judged the MCP server’s responses too heavy to prefer, at 20 to 150 KB per call. It cited repeated container appearance profiles and the same content duplicated as both text and JSON, and chose the API for its ETag support and by_date structure.
Sonnet’s limit on tool output cut the MCP address list for a busy postcode off at 4,000 characters, and it filtered the list itself. Both are concrete costs for agents with small output windows. I’ve since massively reduced the bloat of these MCP responses.
DeepSeek exposed a different gap. Its harness could only make GET requests (asking for things), not POST requests (creating or changing things). So after the address list it asked for the property’s stored schedule, got a 404 no_schedule, and couldn’t create a lookup, which needs a POST. It fell back to navigating the website in its browser.
It also said “I said last time that I prefer the REST API” when it had never run before. OpenClaw carries route judgements across models, so what looked like each model’s own choice is partly inherited. I decided against adding a GET route that creates lookups. Prefetchers, link previews and crawlers treat GETs as safe to fire off, it would put an address in a URL, and it has no idempotency key. Instead I made every 404 no_schedule say what to do next, and made the quickstart say plainly that a lookup needs a POST.
What other write-ups got right and wrong about Muse
Other organisations had already done similar work to this, and had published their conclusions.
| Claim | Source | What I found |
|---|---|---|
| Stock Chrome 153 on Linux, client hints agree, no agent header | Stark Insider, Arkose Labs, DataDome | Confirmed on every session |
| Exits through Cloudflare, or Cloudflare and Fastly | Stark Insider, DataDome | True of the web version (Cloudflare) and of Muse’s own curl traffic (a US block I first took for Fastly). From the Mac app the browser leaves through the user’s own connection, so the address identifies the user, not Muse |
| Mouse moves in curved, human-looking bursts of equal steps | Arkose Labs | Not seen. Muse made one to three mouse moves per click |
| The agent sees an accessibility-tree view and cannot run script in the page | Meta | Consistent. The page’s own script still ran in its browser and reported back |
| Muse will write its own connector for a service with an API | Meta | Consistent. It chose the API unprompted and called it with curl |
| Typing cadence and missing mouse movement separate agents from people | FP-Agent paper (arXiv 2605.01247), written before Muse | Held for Muse on a desktop. Fails on phones, which the paper’s desktop tests didn’t cover |
Sources: Stark Insider, “Meta Muse Specs: What Meta’s Free AI Agent Runs On” (starkinsider.com, 22 September 2026); Arkose Labs, “Every Agent Hides Somewhere. None Hide Everywhere.” (arkoselabs.com, 18 September 2026); DataDome, “Meta’s Muse Is Bringing Agentic Browsing to the Masses” (datadome.co); Meta, “How We Built Safety Into Muse” (research.meta.ai); Wang et al., “FP-Agent: Fingerprinting AI Browsing Agents” (arxiv.org/abs/2605.01247).
The WhenIsBins agent detection rule as it stands
The rule has two stages.
On arrival: likely agent. Desktop Chrome on Linux whose browser reports software graphics. Every desktop Chrome-on-Linux visit is kept so that the page’s script can report this. This catches Muse and misses Instinct. Self-hosted OpenClaw announces itself as headless Chrome.
After the first interaction: agent behaviour. A desktop visit that clicks with fewer than 5 mouse moves per click and, if it typed at least three keys, has under 100 ms between them. A phone is never judged.
Applied to the recorded sessions, every Muse page with a click was marked on both stages. Every Instinct page with a click was marked on the second stage only. Every OpenClaw page with a click was marked on both. Every desktop and laptop session done by hand read as a person. The phone was left unjudged.
To be clear: these rules are easy to defeat: Meta could give the browser a real graphics string, move the mouse first, or slow its typing. And it says nothing about API use, which Muse claims to prefer.
What I still don’t know
The open questions are all about how generalisable any of this is.
Is it only this account? Every Muse observation comes from one account. A second account, ideally one that has never seen WhenIsBins, would show whether the fingerprint and behaviour hold. It would also show whether other Muse accounts share 87.81.224.0/19, which is the one thing left to check before treating the block as Meta’s. Instinct’s own traffic came from a single Google Cloud address, so the rotating pool isn’t a general agent signature. What the two agents share is a cloud exit for the machine and a browser exit that follows the user.
Does the fingerprint differ outside the US? On 9 October I ran Muse from the UK with no VPN. The fingerprint was unchanged apart from Chrome 154 replacing 153. The behaviour marks held (two moves for two clicks, nine keys 70 ms apart). The visit was kept without a label by the desktop-Linux rule, and the exit was a UK broadband address. It also sent X-Agent: Muse unprompted and opened an MCP session as muse-curl.
Will Muse start signing its requests? Earlier this week Meta joined the likes of Shopify and Stripe in stating its support for the “Personal Agent Protocol“, a proposed, as-yet unpublished open standard by which agents will self-declare their presence to services they use. If Muse adopts it, most of this paper becomes moot. Let’s hope that’s what happens.
Where this leaves me
Agents show up in two ways: in a browser, pretending to be a person, or on the API, as a machine that will tell you its name if asked. Three agents from three makers share one browser habit that’s a giveaway: a click with almost no mouse movement, and typing that is either absent or machine-fast, on a desktop. Everything else about their fingerprints differs, and Instinct’s real GPU shows why hardware-based identifiers are a shaky foundation.
Every agent’s own machine leaves through a cloud block that isn’t the user’s (Muse’s rotating pool, Instinct’s Google Cloud address, OpenClaw’s wherever it happens to be hosted), while its browser leaves through, or near, the user. Address rules separate the machine from the browser. They never separate the agent from the person.
On the API, agents are indistinguishable from any other curl or Python client unless they name themselves. X-Agent on the API and clientInfo.name on MCP are what we can count. A hand-rolled MCP client that skips the handshake is only counted if asked for a name on the request itself.
What I need next is more people pointing more agents at WhenIsBins and asking for bin collection dates for addresses. Then ideally telling me they’d done so!
Leave a Reply