Web API History Series • Post 94 of 240
Chapter 94: Before Web Storage—How 1995–1998 Browser Scripting and CGI Taught the Web to Remember
A chronological, SEO-focused guide to Browser storage APIs and richer client applications in web API history and its role in the long evolution of web APIs.
Series: Chronological History of Web APIs — Chapter 94 (1995–1998)
When developers talk about browser storage APIs today, they usually mean localStorage, sessionStorage, IndexedDB, and the Cache API—tools that let rich client apps persist data without round-tripping to the server for every interaction. But if you rewind to 1995–1998, the web’s “memory” looked very different. There was no standardized client database, no promise-based storage API, and certainly no offline-first architecture.
And yet, this era is where the essential pattern was invented: a web application needs a reliable way to preserve state across requests. The solutions were improvised—cookies, hidden form inputs, query strings, and server-side sessions stitched to client hints—but the concept became foundational. Those early mechanisms weren’t just hacks; they were the first practical “storage APIs” in the historical sense: interfaces (often loosely defined) that let the browser and server coordinate continuity.
1995: Scripting arrives, but “state” is still mostly a server problem
In 1995, browser scripting took off in mainstream products, and that changed what developers expected from the client. With JavaScript appearing in Netscape and quickly influencing the competitive browser landscape, pages could react to user actions without a full reload. That was the beginning of richer client behavior—but not richer client storage.
The web’s original interaction model was fundamentally stateless: a browser requests a document; the server returns a document. If the server wanted continuity—like a shopping cart—it needed to invent a way to recognize the same user on the next request.
Developers leaned on a few “state carriers,” each with tradeoffs:
- Query strings: Append state to URLs (e.g.,
?cart=123). Easy to implement, but visible, fragile, and hard to secure. - Hidden form fields: Include state in
<input type="hidden">and submit it back. More structured than query strings, but still sent on every submission and easily tampered with. - Server sessions: Store state server-side and connect it to the client via an identifier passed back and forth. This reduced payload and complexity in HTML, but required a reliable client identifier.
This is the moment where “browser storage” starts to matter historically—not because browsers had elegant APIs, but because the application model demanded memory.
1995–1996: CGI + forms become the early integration surface
In the mid-1990s, the Common Gateway Interface (CGI) paired naturally with HTML forms. A user filled out a form, clicked submit, and a CGI program generated a new HTML page in response. This was a primitive dynamic web app architecture, but it established a key API boundary:
- The browser API surface: HTML forms, HTTP requests, and eventually JavaScript-driven validation or UI tweaks.
- The server integration surface: CGI scripts reading environment variables, parsing query parameters, and emitting HTTP headers and HTML.
In practice, state management bridged those surfaces. A server could keep a session in memory or a file, but the browser still needed to send something back that said “I’m the same user.” That “something” is where cookies became pivotal.
Cookies: the early “storage API” that made sessions viable
Cookies existed before modern web API standardization matured, but by 1995–1998 they became the dominant technique for maintaining continuity across requests. Instead of stuffing identifiers into query strings, servers could send a Set-Cookie header, and browsers would attach the corresponding Cookie header on later requests.
From an API-history perspective, cookies are fascinating because they sit at the boundary of multiple layers:
- HTTP header semantics: A server instructs the browser to store a piece of state.
- Browser persistence rules: The browser decides lifespan, scope (domain/path), and when to attach it.
- JavaScript access (early and controversial): Many implementations exposed cookies to scripts, enabling client logic—but also enabling security and privacy problems that would echo for decades.
Importantly, cookies weren’t just “data storage.” They were identity transport, enabling server sessions at scale. That shaped early web architecture: store real state server-side, store only a session key client-side.
In 1997, an important step toward standardization arrived with the IETF’s HTTP state management work, including RFC 2109 (HTTP State Management Mechanism). Even if browser behavior remained inconsistent in practice, this reflected the industry recognizing that state needed clearer rules—an early hint of what would later become formal, widely documented web platform APIs.
1997: ECMAScript and the rise of richer client behavior (without real client storage)
By 1997, the language story for browser scripting was consolidating. ECMAScript’s first edition (published in 1997) helped define a common core for what had been competing scripting dialects. At the same time, “DOM Level 0” scripting conventions (not a formal standard, but a de facto model) encouraged developers to treat the page as something that could be manipulated, not just rendered.
But even as client interactivity improved, persistent client data remained narrow:
- Cookies (small, header-based, sent on requests)
- Form state (re-posted data, sometimes cached by the browser)
- Plugin- and component-specific storage (for example, via Java applets or ActiveX controls, where behavior depended on the client environment)
This limitation mattered. Developers increasingly wanted “application-like” experiences—remembering preferences, drafts, and partially completed workflows. With only cookies and form tricks, the storage model was constrained, leaky, and security-sensitive.
1997–1998: DHTML-style thinking changes expectations
As browsers competed aggressively in the late 1990s, the idea of “Dynamic HTML” (often abbreviated as DHTML in historical discussions) became a common way to describe pages that updated parts of the UI through scripting and DOM manipulation. While the term itself was more marketing umbrella than single spec, the developer mindset shift was real: the browser was starting to feel like an application runtime.
That shift put pressure on state and storage:
- UI state: What’s open, selected, expanded, or filtered?
- User preferences: Language, layout choices, and saved settings.
- Workflow continuity: Multi-step forms, carts, and “wizard” flows.
Without a purpose-built client storage API, developers repeatedly recycled the same strategies:
- Store a tiny identifier in a cookie; keep the real data server-side.
- Store small preference values directly in cookies.
- Use hidden fields as a “poor man’s session” for short-lived flows.
- Serialize state into URLs (often brittle, sometimes bookmarkable by accident).
This era’s solutions seem crude now, but they established enduring design questions that later storage APIs had to answer: How much data should live on the client? Who can read it? When is it transmitted? What is its lifetime? How is it scoped?
Why this era matters to the history of browser storage APIs
Modern browser storage APIs didn’t appear in 1995–1998, but the need for them became undeniable during this window. By pushing more logic into the client (via scripting) while still relying on server-generated pages (via CGI and similar techniques), developers created a hybrid architecture that demanded better primitives.
In other words, the web learned an important lesson: interactivity without memory is fragile. Cookies and form tricks provided just enough persistence to fuel early e-commerce and personalized sites, but they also exposed limitations that later standards sought to fix—like not sending all stored data on every request, supporting larger structured data, and clarifying security boundaries.
If you enjoy tracing these “how did we get here?” threads from early web plumbing to today’s automation-heavy client apps, you might also like the web platform deep dives at https://automatedhacks.com/, where modern tooling is often explained through the lens of practical constraints.
Key takeaways (1995–1998)
- Cookies became the default state mechanism for identifying users and maintaining server-side sessions.
- CGI + forms defined a core integration style where state had to survive across full page reloads.
- Scripting expanded client capability, but it also highlighted how little durable client storage was available.
- Standardization efforts (like RFC 2109 in 1997) showed the platform recognizing that “remembering” needed clearer rules.
FAQ
Were there any browser storage APIs like localStorage in 1995–1998?
Not in the modern sense. During 1995–1998, persistence was mainly achieved through HTTP cookies, plus workarounds like hidden form fields and URL parameters. Purpose-built web platform storage APIs (with clearer programmatic interfaces and larger capacity) came later.
Why were cookies so important to early dynamic websites?
They gave servers a practical way to recognize a browser across multiple requests. That made shopping carts, logins, and personalized pages workable without forcing developers to embed identifiers into every link and form action.
How did CGI relate to web APIs in this period?
CGI defined a widely used interface between the web server and application code. Combined with HTML forms, it created a repeatable pattern for dynamic content generation—effectively an early “web application API surface”—where state handling became a central problem.
What did RFC 2109 change?
RFC 2109 (published in 1997) was part of the effort to standardize how cookies and state management should work in HTTP. Even though browser behavior didn’t instantly become uniform, it signaled that state was no longer an ad hoc feature—it was becoming a formalized part of web interoperability.
