Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.notte.cc/llms.txt

Use this file to discover all available pages before exploring further.

You can embed any active Notte session directly into your own web app — a Next.js dashboard, an internal tool, a customer-facing demo. The live viewer is just a URL that you render inside an <iframe>.

Live demo

See it running in a minimal Next.js app

Source on GitHub

Clone the template and ship in minutes

How it works

Every active session exposes a viewer_url on its status response. Drop that URL into an <iframe> and you get a live, interactive browser canvas inside your page.
const session = notte.Session({ viewport_width: 1440, viewport_height: 900 });
await session.start();

const status = await session.status();
console.log(status.viewer_url);
// https://console.notte.cc/static/viewer?ws=wss://...&jwt=...
The returned URL is signed with a short-lived JWT scoped to that session, so you can pass it straight to the browser without any extra auth handling on your side.

Quick start (Next.js)

A minimal embed needs two pieces: a server route that creates a session and returns its viewer_url, and a client component that renders the iframe.

1. Server route

Keep the NOTTE_API_KEY on the server. Never ship it to the client.
app/api/session/route.ts
import { NextResponse } from "next/server";
import { NotteClient } from "notte-sdk";

export async function POST() {
  const notte = new NotteClient({ apiKey: process.env.NOTTE_API_KEY! });
  const session = notte.Session({
    max_duration_minutes: 15,
    viewport_width: 1440,
    viewport_height: 900,
  });
  await session.start();

  const status = await session.status();
  return NextResponse.json({
    sessionId: session.getId(),
    viewerUrl: status.viewer_url,
  });
}

2. Client component

app/page.tsx
"use client";
import { useState } from "react";

export default function Home() {
  const [viewerUrl, setViewerUrl] = useState<string | null>(null);

  async function start() {
    const res = await fetch("/api/session", { method: "POST" });
    const { viewerUrl } = await res.json();
    setViewerUrl(viewerUrl);
  }

  return (
    <main>
      <button onClick={start}>Start browser</button>

      {viewerUrl && (
        <iframe
          src={viewerUrl}
          style={{ width: "100%", aspectRatio: "1440 / 940", border: "none" }}
          allow="clipboard-read; clipboard-write"
        />
      )}
    </main>
  );
}
That’s it. Click the button, the iframe fills with a live, fully interactive remote browser.

Embed parameters

The viewer accepts a few query parameters you can append to viewer_url to tune the experience:
ParamValuesEffect
modeembed-minimalShows only the CDP viewer. Without mode=embed-minimal, the iframe shows the full Notte viewer, including the step timeline and Notte branding
interactive0 / 10 makes the iframe 100% non-interactive. 1 requires the user to click the iframe once before they can interact with the embedded browser
themelight / darkForce a theme on the viewer chrome
<iframe src={`${viewerUrl}&mode=embed-minimal&interactive=1&theme=dark`} />

Sizing the viewport

Match the session’s viewport_width / viewport_height to the iframe’s aspect ratio. If the ratios diverge, the screencast canvas letterboxes inside the iframe — the page still renders correctly, just with empty bars on the sides.
notte.Session({ viewport_width: 1920, viewport_height: 1080 }); // 16:9
.viewer { aspect-ratio: 1920 / 1080; }

Stopping the session

Sessions auto-expire after max_duration_minutes, but always provide an explicit stop button so users don’t burn quota on idle iframes.
await session.stop();

Next Steps

Live View

The full live viewer reference

Session Configuration

Viewport, proxies, browser type, and more

Recordings

Replay sessions after they end

Demo repo

Full Next.js example with progress bar, controls, and styling