Skip to main content

Your first script

Let’s create a simple script that opens a browser, navigates to a page, and takes a screenshot.
1

Create a new Python file

Create a file called first_script.py:
import nodriver as uc

async def main():
    # Start the browser
    browser = await uc.start()
    
    # Navigate to a page
    page = await browser.get('https://www.nowsecure.nl')
    
    # Take a screenshot
    await page.save_screenshot()
    
    print("Screenshot saved!")
    
    # Clean up
    browser.stop()

if __name__ == '__main__':
    # Run the async function
    uc.loop().run_until_complete(main())
2

Run the script

python first_script.py
You should see a browser window open, navigate to the page, and then close. A screenshot will be saved in your current directory.
nodriver uses uc.loop().run_until_complete() instead of asyncio.run() for better compatibility and control.

Understanding the basics

Starting a browser

The start() function launches a browser and returns a Browser instance:
import nodriver as uc

# Basic start
browser = await uc.start()

# With options
browser = await uc.start(
    headless=False,  # Show the browser window
    browser_args=['--window-size=1920,1080']
)
By default, nodriver creates a fresh profile that’s automatically cleaned up when the browser closes. This ensures a clean state for each run.
Use browser.get() to navigate:
# Open in the main tab
page = await browser.get('https://www.google.com')

# Open in a new tab
page2 = await browser.get('https://www.github.com', new_tab=True)

# Open in a new window
page3 = await browser.get('https://www.stackoverflow.com', new_window=True)

Finding elements

nodriver provides multiple ways to find elements on a page:
# Find by text content (smart matching)
button = await page.find("accept all")
await button.click()

# Find with best match (shortest text wins)
login_btn = await page.find("login", best_match=True)

# Find all occurrences
links = await page.find_all("click here")
All find methods automatically wait for elements to appear (default timeout: 2.5 seconds). This eliminates the need for explicit waits in most cases.

Interacting with elements

Once you have an element, you can interact with it:
# Click an element
await element.click()

# Type text
await input_field.send_keys("search query")

# Clear input
await input_field.clear_input()

# Get text content
text = await element.text

# Get attributes
href = await link.get_attribute('href')

# Mouse operations
await element.mouse_move()
await element.mouse_drag([250, 250], relative=True)

# Scroll into view
await element.scroll_into_view()

# Flash element (visual debugging)
await element.flash()

Real-world example

Let’s build a script that searches Google:
import nodriver as uc

async def google_search():
    browser = await uc.start()
    
    # Navigate to Google
    tab = await browser.get("https://www.google.com/?hl=en")
    
    # Handle cookie consent if present
    reject_btn = await tab.find("reject all", best_match=True)
    if reject_btn:
        await reject_btn.click()
    
    # Find search input (it's a textarea on Google)
    search_input = await tab.select("textarea")
    
    # Type search query
    await search_input.send_keys("undetected nodriver")
    
    # Find and click search button
    search_btn = await tab.find("google search", best_match=True)
    await search_btn.click()
    
    # Wait for results and scroll
    await tab.sleep(2)
    for _ in range(3):
        await tab.scroll_down(100)
        await tab.sleep(0.5)
    
    # Get all search result links
    results = await tab.select_all("h3")
    print(f"Found {len(results)} results")
    
    for i, result in enumerate(results[:5], 1):
        text = await result.text
        print(f"{i}. {text}")
    
    # Take a screenshot
    await tab.save_screenshot("google_results.png")
    
    browser.stop()

if __name__ == '__main__':
    uc.loop().run_until_complete(google_search())
This example is adapted from the real examples in the nodriver repository. Check example/network_monitor.py for the full source.

Working with multiple tabs

nodriver makes it easy to manage multiple tabs:
import nodriver as uc

async def multi_tab_example():
    browser = await uc.start()
    
    # Open multiple tabs
    tab1 = await browser.get('https://www.github.com')
    tab2 = await browser.get('https://www.stackoverflow.com', new_tab=True)
    tab3 = await browser.get('https://www.google.com', new_tab=True)
    
    # Iterate through all tabs
    for tab in browser.tabs:
        await tab.activate()
        print(f"Current URL: {tab.url}")
        await tab.scroll_down(200)
        await tab.sleep(1)
    
    # Close specific tab
    await tab2.close()
    
    # Close all except main tab
    for tab in browser.tabs:
        if tab != browser.main_tab:
            await tab.close()
    
    browser.stop()

if __name__ == '__main__':
    uc.loop().run_until_complete(multi_tab_example())

Advanced configuration

Customize browser behavior with the Config object:
from nodriver import Config, start

async def advanced_setup():
    # Create config
    config = Config()
    config.headless = False
    config.browser_args = [
        '--window-size=1920,1080',
        '--start-maximized'
    ]
    
    # Use custom profile (won't be auto-cleaned)
    config.user_data_dir = "/path/to/profile"
    
    # Use specific browser
    config.browser_executable_path = "/path/to/chrome"
    
    # Start with config
    browser = await start(config=config)
    
    # Your automation here
    page = await browser.get('https://example.com')
    
    browser.stop()
Or pass options directly to start():
browser = await uc.start(
    headless=False,
    user_data_dir="/path/to/profile",
    browser_executable_path="/path/to/chrome",
    browser_args=['--window-size=1920,1080'],
    lang="en-US"
)

Handling common scenarios

# Wait for body element (indicates page loaded)
await tab.select('body')

# Or use sleep for a specific duration
await tab.sleep(2)

# Wait for events to process
await tab  # Short wait for CDP events
nodriver automatically searches within iframes when using find() and select() methods:
# Searches in main frame and iframes
element = await tab.select("#element-in-iframe")
# Find methods retry until timeout
# This element will be found once it appears
button = await tab.find("submit", timeout=10)

# For elements that might not appear
optional_elem = await tab.find("optional text")
if optional_elem:
    await optional_elem.click()
# Save screenshot with default name
await tab.save_screenshot()

# Custom filename
await tab.save_screenshot("my_screenshot.png")

# Get page content
html = await tab.get_content()

Common patterns

Form filling

async def fill_form():
    browser = await uc.start()
    tab = await browser.get('https://example.com/form')
    
    # Fill text inputs
    name_input = await tab.select("input[name='name']")
    await name_input.send_keys("John Doe")
    
    email_input = await tab.select("input[type='email']")
    await email_input.send_keys("[email protected]")
    
    # Select from dropdown
    dropdown = await tab.select("select[name='country']")
    await dropdown.send_keys("United States")
    
    # Submit form
    submit_btn = await tab.select("button[type='submit']")
    await submit_btn.click()
    
    browser.stop()
async def cookie_example():
    browser = await uc.start()
    tab = await browser.get('https://example.com')
    
    # Perform login or other actions
    # ...
    
    # Save cookies to file
    await tab.save_cookies('cookies.json')
    
    # Later, load cookies
    browser2 = await uc.start()
    tab2 = await browser2.get('https://example.com')
    await tab2.load_cookies('cookies.json')
    
    # Now logged in without repeating login steps

Next steps

Now that you understand the basics, explore more advanced features:

API Reference

Explore the complete API documentation

Examples

Learn from real-world automation scripts

Browser class

Deep dive into browser control and configuration

Tab class

Master page interaction and element manipulation

Build docs developers (and LLMs) love