Netra is a predictive HTML parser and streaming toolkit for the Vercel AI SDK. It balances unfinished documents for instant iframe rendering while keeping the model stream as the source of truth — so generative UI builds up smoothly instead of popping in at the end.
Netra is in an early research phase. The packaged backend helper targets the Vercel AI SDK only for now. A lower-level, provider-agnostic adapter (streamHtmlArtifactFromTextStream) exists for other runtimes, but APIs may still change between alpha releases.
Why HTML
Markdown caps you at text and tables. Custom component runtimes ship a renderer and diff every token. HTML needs neither: stream it straight into a sandboxed iframe with safe-render techniques that keep the client light and the main thread free.
Every device ships a world-class HTML/CSS engine. Netra streams straight into it — no bespoke component runtime, no React-over-the-wire, no translation layer between the model and the pixels.
Artifacts mount in a sandboxed iframe with sanitized HTML. Scripts can be enabled for trusted embeds and final-page interactions while the stream still paints safely first.
Each frame is balanced once by the predictive parser and patched into the live iframe in place — no re-mounting React trees per token, no virtual-DOM diffing of streamed markup. Far less main-thread work.
Parsing is incremental (O(n)), paints are throttled to animation frames, and the iframe is never reloaded mid-stream. The UI builds up smoothly while the main thread stays free to scroll, type, and click.
Server + client
Wrap a Vercel AI SDK model on the server, render the stream on the client. The parser, sanitizer, SSE protocol and iframe runtime are all handled for you.
// app/api/chat/route.ts
import { createGoogleGenerativeAI } from "@ai-sdk/google";
import { generateText, streamText } from "ai";
import { createArtifactStreamResponse } from "netra-artifacts/server";
export const dynamic = "force-dynamic";
const google = createGoogleGenerativeAI();
export async function POST(req: Request) {
const { messages } = await req.json();
const model = google("gemini-2.5-flash");
// Streams markdown OR a sandboxed HTML artifact — automatically.
return createArtifactStreamResponse({
messages,
generateTextStream: (args) =>
streamText({ model, ...args }).textStream,
generateText: async (args) =>
(await generateText({ model, ...args })).text,
mode: "auto",
});
}// components/Chat.tsx
"use client";
import { useArtifactStream, ArtifactMessage } from "netra-artifacts/client";
export function Chat() {
const { messages, artifacts, sendMessage } = useArtifactStream({
endpoint: "/api/chat",
});
return (
<>
{messages.map((m) => (
<ArtifactMessage key={m.id} message={m} artifacts={artifacts} />
))}
<button onClick={() => sendMessage("A pricing page for a SaaS")}>
Generate UI
</button>
</>
);
}Streaming protocol
artifact_delta carries the exact model output. artifact_snapshot is the parser-balanced, sanitized frame ready for the iframe. artifact_done is the final, authoritative document.
Incomplete model output is projected into a valid document by predicting closing tags — the raw stream stays the source of truth.
An auto classifier streams plain markdown when text suffices, or a rich HTML artifact when the answer deserves a visual.
Every artifact renders in a sandboxed iframe. The body and CSS stream first; optional final scripts can enhance trusted embeds and interactions.
One persistent parser feeds only new tokens; frame-throttled, in-place iframe patches mean the UI builds smoothly with no reload flash.
Each artifact card ships copy-HTML, download-HTML and native print-to-PDF — no extra dependencies.
Google, Anthropic, OpenAI, DeepSeek and OpenRouter all work through the same SSE protocol and provider headers.