Inspiration

The biggest screen in my house can't open a website. Every evening, on the sofa, right in front of it, we squint at our phones: a recipe, a sofa we might buy, the local news.

TVs mostly gave up on the web. Some platforms ship no browser at all, and the usual advice is "cast it from your phone". Where a TV browser exists, it is a desktop browser with a cursor you push around with arrow keys. The new AI bet on TVs goes the other way: answer assistants that read the web for you and show a summary. Publishers are suing over that model, because the summary takes the visit.

So I asked the opposite question: what if the AI didn't replace the page, but made the real page work from the remote? Answer engines take the visit. A browser gives it back.

What it does

Sofa Surf is a web browser for Fire TV, built on Vega OS. It shows the publisher's real page, and Amazon Nova makes that page work from the sofa.

  • Every website becomes its own Fire TV app (Sofa mode). While Nova reads the page, Sofa Surf's address bar shows; then it cross-fades into the site's own app bar: its icon, name and colour from its web app manifest, and its menu as TV tabs. The page is laid out at sofa size in the site's own responsive layout. One press adds the site to Home, like any app.
  • The D-pad moves between the page's real parts. Titles, sections, products and stories become focus stops, with a rail on the left ("On this page"). ◀◀ ▶▶ jump section to section, or page to page. OK reads from here, or opens.
  • Pop-ups gone, ads kept. Newsletter, sign-up and chat prompts that cover the page are closed as it opens. Ads are never touched.
  • Ask this page, and see where. Menu opens a panel with three questions Nova thinks a viewer would really ask about this page. Nova answers only from what's written there, and the answer carries the page's own words. OK on a quote scrolls the page to it and highlights it. If the page doesn't say, Sofa Surf says "Not on this page" instead of guessing.
  • Cook mode. ▶❚❚ on a recipe gives one step per screen, readable from the stove, with a timer read from the step's own text ("about 9 minutes"). The live page stays underneath, so Back returns to the same spot.
  • Actions only through the site's own tools. On a shop, ▶❚❚ runs a tool the site declares through WebMCP (navigator.modelContext), such as Add to cart. A confirm sheet shows what the site says the tool does, and nothing happens without the viewer's OK. The site's own code does the work.
  • Paywalls stand. On a subscriber story the paywall stays up, and Ask refuses to read behind it: "This page is for subscribers. Sofa Surf won't read it for you: sign in on your phone to read it here."
  • Continue on your phone. A QR code opens the same page on the phone, for signing in, paying or typing.

For site owners: zero effort, full control

A site can… How
Get a Fire TV app with no work Nothing to do: the manifest, meta tags and menu it already has become the app
Look its best A web app manifest (name, icons, theme_color), schema.org (Recipe, Product, Article), a few CSS lines for html[data-sofasurf]
Offer actions on the remote WebMCP tools; each one is confirmed by the viewer
See its TV traffic Every request says SofaSurf/1.0 in the user agent
Turn the AI off <meta name="sofasurf" content="noai"> keeps browsing but turns Nova off

Nova reads a page only when a viewer opens it, for that viewer. Sofa Surf never crawls, never shows a summary in place of the page, never hides an ad and never jumps a paywall.

How we built it

Part What it is
TV app React Native for Vega 0.83 (Vega SDK 0.24), with the page in @amazon-devices/webview 4.0.2. Native layers (app bar, rail, Ask panel, sheets, Cook mode) render above the WebView
Page script Injected into every page before content loads: a map of focus stops, the focus engine and its ring, the pop-up clean-up (consent, sign-up, chat; never ads or paywalls), a paywall check, site identity (manifest, meta tags, nav), a WebMCP shim, and the quote finder and highlighter
Nova Amazon Nova 2 Lite (nova-2-lite-v1) through the Amazon Nova API. One call per page labels the parts and writes the three questions (about 700 tokens, about 2 s); one call per question answers it
Grounding A small rule on the server: a quote must appear word for word in the page, and a number in the answer must appear in a quote. Anything else is dropped, and the answer becomes "Not on this page"
Backend FastAPI: page metadata, image resizing for the TV, Nova calls cached per page, QR codes
Demo sites Three fictional sites I made so the video shows no third-party brands: a recipe blog, a furniture shop with WebMCP tools, a local newspaper with a paywall. Each has a manifest, an icon and its own art

Measured on the Virtual Device with real Nova calls: the remote is ready on a page in 0.5–2.2 s, Nova's read of the page takes 2.0–4.4 s, and an answer 1.6–4.7 s. About 2,200 lines of TypeScript and 590 of Python, with a friction log of 14 Vega findings and a top-5 list for the next Vega version.

Challenges we ran into

  • Two runtimes hear every key. The remote's arrows, OK and media keys reach the page and the React Native app at the same time, and nothing documents who owns them. When the Ask panel opened, the D-pad moved the panel and the page underneath. I made Menu the AI key (the one key the page never gets), and the app pauses the page script whenever a native layer is open.
  • The page bridge doesn't exist at document start, and an exception in the injected script is silent: no error, no log. A one-line bug (appending to a document.head that doesn't exist yet) took an hour of rebuild-and-probe cycles to find. Every message now goes into a queue, and the script reports its own errors.
  • The WebView zooms the page out when one element is too wide, and on one site it stopped applying the viewport after load. The page script now pins the scale and re-inserts a fresh viewport tag when the width drifts.
  • No WebView DevTools on the Virtual Device, so everything was debugged with postMessage probes.
  • Keeping Nova honest. A language model will happily answer a question the page doesn't answer. The grounding rule throws away any answer it can't point to on the page. That costs a few refusals, and I prefer a refusal to a guess.
  • Being an ally, not a scraper. Every rule that keeps publishers on our side (ads untouched, paywalls standing, a declared user agent, actions only through declared tools) is enforced in code, not just promised.

Accomplishments that we're proud of

  • The moment a website turns into a Fire TV app in about two seconds, with its own colours and menu, and the page underneath is still the publisher's real page.
  • An answer that points into the page: OK on the quote scrolls there and lights it up. You can't do that on a desktop without reading the page yourself.
  • A shop action that goes through the site's own code, after the viewer's OK, in the way Amazon has asked AI agents to behave.
  • A friction log that maps the OS ↔ app ↔ WebView boundary on Vega, which I'd have loved to read on day one.

What we learned

  • On a TV, the AI's best job is not to write: it is to point. The remote has nine buttons, and the page already has the content.
  • The web already carries most of what a TV app needs (manifests, schema.org, nav menus). Sofa Surf mostly reads what sites already publish.
  • Vega's WebView is capable: native layers above it, injected scripts, the remote's keys in the page. Its boundaries just need writing down.

What's next

  • The real stick: measure time to first focus, Nova p50/p95 and memory on a Fire TV Stick (so far it has run on the Vega Virtual Device).
  • A 20-site evaluation of focus coverage, grounded vs refused answers and paywalls respected, driven by Nova Act.
  • Amazon Bedrock and AgentCore in place of the Nova API, with a shared cache and cost per 1,000 pages.
  • Alexa+: "Alexa, open Lina's Kitchen" opens the site as an app; "Alexa, how long does it cook?" answers and points at the page. Typing a question with the phone as keyboard.
  • A page for site owners with the rules above and the SofaSurf opt-outs.

Built With

Share this project:

Updates

Submission history