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.

Notte sessions expose a Chrome DevTools Protocol (CDP) endpoint that you can connect to with Puppeteer. Since Puppeteer is a Node.js library and Notte SDK is Python-based, this guide shows how to connect them together.

Prerequisites

Install Puppeteer in your Node.js project:
npm install puppeteer-core
Use puppeteer-core instead of puppeteer since you’re connecting to a remote browser rather than launching a local one.

Approach 1: Start Session from Python

Start a Notte session in Python and connect Puppeteer to it:
from notte_sdk import NotteClient
import subprocess
import json

client = NotteClient()

with client.Session(timeout_minutes=10) as session:
    cdp_url = session.cdp_url()

    # Pass CDP URL to Node.js script
    result = subprocess.run(
        ["node", "puppeteer_script.js", cdp_url],
        capture_output=True,
        text=True
    )

    print(result.stdout)

Approach 2: Use Notte REST API

Call the Notte API directly from Node.js to create sessions:
const puppeteer = require('puppeteer-core');
const fetch = require('node-fetch');

async function createNotteSession() {
  const response = await fetch('https://api.notte.cc/sessions/start', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.NOTTE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      headless: true,
      timeout_minutes: 10,
      browser_type: 'chromium'
    })
  });

  return await response.json();
}

async function main() {
  // Start Notte session
  const sessionData = await createNotteSession();
  const cdpUrl = sessionData.cdp_url;
  const sessionId = sessionData.session_id;

  console.log(`Session started: ${sessionId}`);

  try {
    // Connect Puppeteer
    const browser = await puppeteer.connect({
      browserWSEndpoint: cdpUrl
    });

    const pages = await browser.pages();
    const page = pages[0];

    // Use Puppeteer
    await page.goto('https://example.com');
    console.log('Title:', await page.title());

    await browser.disconnect();
  } finally {
    // Stop session
    await fetch(`https://api.notte.cc/sessions/${sessionId}/stop`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.NOTTE_API_KEY}`
      }
    });
  }
}

main().catch(console.error);

Network Interception

Use Puppeteer’s request interception with Notte sessions:
const puppeteer = require('puppeteer-core');

async function main() {
  const cdpUrl = process.argv[2]; // From Python or API

  const browser = await puppeteer.connect({
    browserWSEndpoint: cdpUrl
  });

  const pages = await browser.pages();
  const page = pages[0];

  // Enable request interception
  await page.setRequestInterception(true);

  // Block images and stylesheets
  page.on('request', (request) => {
    if (['image', 'stylesheet', 'font'].includes(request.resourceType())) {
      request.abort();
    } else {
      request.continue();
    }
  });

  await page.goto('https://example.com');
  console.log('Page loaded without images');

  await browser.disconnect();
}

main().catch(console.error);

Page Manipulation

Use Puppeteer’s API for advanced page interactions:
const puppeteer = require('puppeteer-core');

async function main() {
  const cdpUrl = process.argv[2];

  const browser = await puppeteer.connect({
    browserWSEndpoint: cdpUrl
  });

  const pages = await browser.pages();
  const page = pages[0];

  await page.goto('https://example.com/login');

  // Type into inputs
  await page.type('input[name="email"]', 'user@example.com');
  await page.type('input[name="password"]', 'password123');

  // Click button
  await page.click('button[type="submit"]');

  // Wait for navigation
  await page.waitForNavigation();

  // Extract data
  const title = await page.title();
  const content = await page.evaluate(() => {
    return document.querySelector('h1')?.textContent;
  });

  console.log('Title:', title);
  console.log('Content:', content);

  await browser.disconnect();
}

main().catch(console.error);

Multiple Pages

Create and manage multiple pages with Puppeteer:
const puppeteer = require('puppeteer-core');

async function main() {
  const cdpUrl = process.argv[2];

  const browser = await puppeteer.connect({
    browserWSEndpoint: cdpUrl
  });

  // Create new pages
  const page1 = await browser.newPage();
  const page2 = await browser.newPage();

  await page1.goto('https://example.com');
  await page2.goto('https://google.com');

  console.log('Page 1:', await page1.title());
  console.log('Page 2:', await page2.title());

  // Close specific pages
  await page2.close();

  await browser.disconnect();
}

main().catch(console.error);

Event Monitoring

Listen to browser events using Puppeteer:
const puppeteer = require('puppeteer-core');

async function main() {
  const cdpUrl = process.argv[2];

  const browser = await puppeteer.connect({
    browserWSEndpoint: cdpUrl
  });

  const pages = await browser.pages();
  const page = pages[0];

  // Listen to console messages
  page.on('console', (msg) => {
    console.log('Browser console:', msg.text());
  });

  // Listen to page errors
  page.on('pageerror', (error) => {
    console.error('Page error:', error.message);
  });

  // Listen to requests
  page.on('request', (request) => {
    console.log('Request:', request.url());
  });

  // Listen to responses
  page.on('response', (response) => {
    console.log('Response:', response.url(), response.status());
  });

  await page.goto('https://example.com');

  await browser.disconnect();
}

main().catch(console.error);

Screenshots and PDFs

Generate screenshots and PDFs using Puppeteer:
const puppeteer = require('puppeteer-core');

async function main() {
  const cdpUrl = process.argv[2];

  const browser = await puppeteer.connect({
    browserWSEndpoint: cdpUrl
  });

  const pages = await browser.pages();
  const page = pages[0];

  await page.goto('https://example.com');

  // Take screenshot
  await page.screenshot({
    path: 'screenshot.png',
    fullPage: true
  });

  // Generate PDF
  await page.pdf({
    path: 'page.pdf',
    format: 'A4',
    printBackground: true
  });

  console.log('Screenshot and PDF saved');

  await browser.disconnect();
}

main().catch(console.error);

Best Practices

1. Use puppeteer-core

Always use puppeteer-core instead of puppeteer since you’re connecting to a remote browser:
npm install puppeteer-core

2. Handle Disconnections

CDP connections can be interrupted. Always wrap operations in try-catch:
try {
  const browser = await puppeteer.connect({
    browserWSEndpoint: cdpUrl
  });
  // ... operations
} catch (error) {
  console.error('Connection failed:', error);
}

3. Disconnect Properly

Always disconnect the browser when done:
try {
  // ... operations
} finally {
  await browser.disconnect();
}

4. Session Timeout

Remember that Notte sessions have a timeout. Set an appropriate value when creating the session:
puppeteer_session_timeout.py
from notte_sdk import NotteClient

client = NotteClient()

# In Python
with client.Session(idle_timeout_minutes=20) as session:
    # Long Puppeteer operations
    pass

5. Environment Variables

Store your Notte API key in environment variables:
const API_KEY = process.env.NOTTE_API_KEY;

Complete Example: Web Scraping

Here’s a complete example combining Notte and Puppeteer for web scraping:
const puppeteer = require('puppeteer-core');
const fetch = require('node-fetch');

async function scrapeWithNotte() {
  // Create Notte session
  const sessionResponse = await fetch('https://api.notte.cc/sessions/start', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.NOTTE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      headless: true,
      proxies: true,  // Use residential proxies
      solve_captchas: false,
      timeout_minutes: 15,
      browser_type: 'chromium'
    })
  });

  const session = await sessionResponse.json();
  const { cdp_url, session_id } = session;

  try {
    // Connect Puppeteer
    const browser = await puppeteer.connect({
      browserWSEndpoint: cdp_url
    });

    const pages = await browser.pages();
    const page = pages[0];

    // Navigate and scrape
    await page.goto('https://example.com/products', {
      waitUntil: 'networkidle2'
    });

    // Extract data
    const products = await page.evaluate(() => {
      const items = document.querySelectorAll('.product');
      return Array.from(items).map(item => ({
        title: item.querySelector('.title')?.textContent,
        price: item.querySelector('.price')?.textContent,
        url: item.querySelector('a')?.href
      }));
    });

    console.log('Scraped products:', products);

    await browser.disconnect();
  } finally {
    // Stop session
    await fetch(`https://api.notte.cc/sessions/${session_id}/stop`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.NOTTE_API_KEY}`
      }
    });
  }
}

scrapeWithNotte().catch(console.error);

When to Use Puppeteer with Notte

Use Puppeteer directly when you need:
  • Node.js ecosystem: Integrate with Node.js applications and packages
  • Familiar Puppeteer API: You’re already comfortable with Puppeteer’s API
  • Request interception: Block resources or modify requests
  • Performance monitoring: Track page metrics and performance
  • PDF generation: Create PDFs from web pages
For Python-based automation, consider using Playwright with Notte instead, as it has better Python integration.

Next Steps

Connect with Playwright

Use Playwright with Notte sessions

Connect with Selenium

Use Selenium with Notte sessions

External Browser Providers

Connect Notte to Kernel.sh and other providers

API Reference

Explore the Notte REST API