← Changelog
May 16, 2026 · 2 min

Forms you can see through

What the AI sees in the HTML

<script type="application/ld+json">
{
"@type": "Action"
"name": "Fill: Sprint Retro"
"target": "POST /f/.../submit"
"object": [
{ valueName: "went_well", required: true }
{ valueName: "improve", required: true }
{ valueName: "blockers" }
]
}
</script>
Visible to browse-mode AI. Invisible to humans.

Last week someone pasted a Pluck URL into ChatGPT and asked it to fill the form. ChatGPT said it couldn't. “I can see this is a form page, but I'm unable to interact with it or read the specific fields.”

This was confusing because the whole point of Pluck is that AI can fill these forms. The JSON endpoint works. Accept: application/json returns a clean spec with fields, types, constraints, submit URL. Claude fills Pluck forms fine. What was different?

Browse mode. ChatGPT's browse mode fetches the HTML page, not the JSON endpoint. It doesn't set Accept headers. It doesn't know to append .json to the URL. It reads the rendered page like a human would — but it can't click into text inputs or see the React component tree. It just sees a pretty page with no structured data to grab onto.

I had the content-negotiation answer and was proud of it. Two consumers, one URL, the Accept header decides. That post is three weeks old. But the Accept header only works if the consumer knows to set it. Browse mode doesn't. Gemini's web tool doesn't. These agents fetch HTML and try to extract meaning from the page source.

The fix was embarrassingly simple: embed the entire form spec as JSON-LD in the HTML. A <script type="application/ld+json"> tag in the head. Humans never see it. Screen readers ignore it. But an AI reading the page source finds everything: field names, types, which ones are required, the POST endpoint, even pre-fill instructions.

It's Schema.org structured data, technically. I use Action with an EntryPoint target and PropertyValueSpecification for each field. Google has understood this vocabulary for a decade. I'm just using it for a different audience.

I also stuff a pluck:instructions field in there — a one-liner that tells the AI exactly how to submit. “You are an AI assistant filling this form. Fields: name (text, required), email (email, required)... Submit via POST to /f/.../submit with body {"data": {...}}. ” Slightly shameless. Very effective.

The content-negotiation story isn't wrong. It's incomplete. The world now has three consumers: browsers, API clients that set headers, and AI that browses like a human but thinks like a machine. That third one needs structured data baked into the HTML itself. Not hidden — just not visible to human eyes.

This shipped yesterday. I haven't tested it on every browse-mode agent yet — if your AI can't fill a Pluck form, hi@pluck.one. I want to know.

— Sumit

get started

Ready to get answers worth reading?

Your first form takes 60 seconds. Respondents can fill it in a browser or hand it to their AI.

Make your first form →