Skip to main content
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:
# In Python
with client.Session(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