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:
Python - Start Session
Node.js - Connect Puppeteer
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