From IE6 to AI shells: the browser stopped being a window — here’s what I’d build for now
Casey Holt
September 18, 2026
I learned to ship for IE6 by treating the browser as a hostile window: a box that rendered HTML if you were lucky, scripted if you were careful, and died if you assumed a standard. We built for Chrome-plus-fallbacks for a decade after that. Progressive enhancement. Evergreen clients. A SPA that assumed a human with a mouse and a tab.
That window is still there. It is no longer the only reader. The new browser is an agent with a URL bar — a model that fetches, summarizes, fills forms, and clicks on behalf of someone who may never see your hero animation. I still design for people. I now also design for a non-human that will lie about what it saw if I only offer a canvas and a prayer.
What actually changed
Humans still open Chrome, Safari, Firefox, Edge. They still hate cookie banners. That job did not vanish. What changed is the second client: assistants that browse, coding agents that open your docs, and in-browser side panels that treat your page as a tool. They do not care about your 12-column grid. They care about whether the price is in the HTML, whether the form has a name, whether the API you already expose for the SPA is documented enough to call without the React tree.
IE6 taught me to be conservative about the platform. The AI shell teaches me to be conservative about information. If the only copy of the fare rules is in a PNG or a client-rendered div that arrives after three fetches, the agent will invent the fare. I have watched it invent the fare. The user then argued with support using a number we never published.
I stopped designing for “Chrome plus fallbacks” as the primary sentence. The primary sentence is: a human can complete the task, and a machine can extract the facts without executing our entire JavaScript novel.
What I would build for now
Documents that are documents. The important nouns — price, inventory, policy, status — live in HTML or in a linked machine-readable form (JSON-LD where it is honest, an OpenAPI for the real API, a plain table). I am not a semantic-web romantic. I am tired of support tickets that quote a chatbot.
Forms that are forms. A <form> with a real action or a documented API. Accessible names. Errors in text. I can still enhance with React. I will not make the only submit path a click handler on a div. Agents and accessibility users fail the same way on that div. That is not a coincidence.
A public read API for anything we already show. If the page can see it, a documented GET should be able to see it, with a cache policy I would actually put in the contract. The SPA becomes a client, not the source of truth. The agent era made that a product requirement.
Progressive enhancement that includes “no JS.” Not because I hate SPAs. Because the agent’s fetch may not run our bundle the way we think, and because a degraded human session still happens. A useful first HTML is a feature again.
Permissions and origin honesty. If I build a browser extension or a side panel, I ask for the least. I do not scrape my own site through a user-owned agent with a key in localStorage. That pattern is how we get a security review that lasts a quarter.

What I would not build
I would not build a marketing site that is empty without JavaScript and then buy an “AI search” product to re-index the emptiness. I would not put the only checkout in a canvas. I would not block all bots and then wonder why our docs do not show up in the tools our own engineers use. Allow the ones we mean. Rate-limit the rest. Publish a llms.txt or a docs index if we want to be polite. I treat those as hints, not as SEO magic.
I would not redesign the entire product as a chat. Chat is a client. The system of record is still a system of record. The IE6 era had people who thought the browser was the application. The 2026 era has people who think the prompt is the application. Both are wrong in the same way.
I would not chase every new Chromium AI API the week it ships. I will use a stable extraction path. I will add a fancy on-device summary when it degrades to the same HTML facts.
Auth, personalization, and the agent
Logged-in HTML is not a public fact. I do not want an assistant quoting my invoice to the wrong chat. Public pages get public nouns. Private pages stay behind auth the agent cannot skip. If we offer a “summarize my account” feature, that is an authenticated API with a user’s token, not a scrape of /account with a stolen cookie. I have seen the scrape version proposed as “just use the existing page.” Existing pages have CSRF and session assumptions. An agent is not a user with a session unless we made it one on purpose.
Personalization that swaps prices in JS after load is the $0 fare bug wearing a hoodie. If the price depends on the user, the first HTML should say so — “sign in to see your rate” — not show a dummy number. Dummy numbers become citations.
How I would ship a page this month
Content in the document. Enhancement in the bundle. API for the data the page shows. Tests that assert the nouns in the HTML, not only the pixels in Playwright. A crawl of the critical path with JS off in CI, once, so we notice when we broke the document.
For an app that must be a SPA — a canvas editor, a trading blotter — I still build the SPA. I also export a read model: a summary endpoint, a shareable snapshot, something an agent can fetch without driving the canvas. The editor is for humans. The snapshot is for everyone else.
I keep the old fallbacks that still matter: Safari dates, iOS overflow, a reduced-motion path. I drop the IE11 polyfill museum. I drop user-agent sniffing for “Chrome vs the rest” except where a real bug forces it. The new sniff I refuse is “is this an agent.” Detecting agents to show a poorer page is how you get two products and one lawsuit-shaped headline. Detect capabilities. Offer facts.

A support week that changed my defaults
A travel page showed fares in a React island that hydrated late. An assistant summarized the page from the first HTML, which had a placeholder of $0. Three customers booked an argument, not a trip. We put the fare in the initial document and kept the island for the calendar UX. Tickets dropped. The design did not get worse. The document got honest. I now treat late-hydrated money as a defect, not as a performance flex.
The same week, our docs site was a SPA with no HTML titles for the actual procedure. The coding agent kept missing the “rotate the key” page because the index saw a shell. We rendered the procedure in the document. The agent found it. So did the intern. Same fix, two clients.
The line from IE6 I still use
Assume the client is hostile to your assumptions. IE6 was hostile to standards. The agent is hostile to implied meaning. Both reward you for putting the truth in a boring place. Both punish you for a clever presentation that is the only copy of the truth.
I would rather ship a slightly plainer page that a model can quote correctly than a cinematic one that becomes a rumor. Designers I like can still make the plain page beautiful. They cannot make a rumor unsend.
From IE6 to AI shells, the browser stopped being only a window. It is a window and a tool-using reader. I build the document and the API for both. I build the animation for the person who asked for it. I do not build the truth exclusively inside the animation.
If you are choosing this week: pick one user task, view source with JS disabled, and ask whether an intern — human or model — could state the price and the next action. If they cannot, you are still designing for a window that no longer exists as the only client. Fix the document. Then invite the agent in. That is what I would build for now, and it looks more like 2008 craft than like a keynote. I am fine with that. The keynote will change again. The document will still be there, which is the only continuity I have trusted since the weekend we dropped IE6 and thought we were done being careful.
We were not done. We are not done. The shell got smarter. The need for a boring source of truth got louder. I will keep building that, and I will let the window be pretty after the truth has a URL.