Skip to main content

Create a Session

Start a remote browser session and get the CDP connection URL:
from tinyfish import TinyFish

client = TinyFish()
session = client.browser.sessions.create(url="https://example.com")

print(f"Session: {session.session_id}")
print(f"CDP URL: {session.cdp_url}")
print(f"Base URL: {session.base_url}")
Output:
{
  "session_id": "tf-84ac6714-0f08-4592-b626-e51105a079f9",
  "cdp_url": "wss://ip-52-53-175-49.tetra-data.tinyfish.io/tf-84ac6714-...",
  "base_url": "https://ip-52-53-175-49.tetra-data.tinyfish.io/tf-84ac6714-..."
}

Connect with Playwright

Create a session and control it with Playwright via CDP:
import asyncio
from playwright.async_api import async_playwright
from tinyfish import TinyFish

async def main():
    client = TinyFish()
    session = client.browser.sessions.create(url="https://scrapeme.live/shop")

    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(session.cdp_url)
        page = browser.contexts[0].pages[0]

        await asyncio.sleep(2)
        await page.wait_for_load_state("domcontentloaded")

        title = await page.title()
        print(f"Page title: {title}")

        await page.screenshot(path="shop.png")
        print("Screenshot saved to shop.png")

asyncio.run(main())
Session creation takes 10-30 seconds. Set your HTTP client timeout to at least 60 seconds. The browser navigates to the URL asynchronously — wait for domcontentloaded before interacting.

Scrape with Playwright

Extract structured data from a page using Playwright selectors:
import asyncio, json
from playwright.async_api import async_playwright
from tinyfish import TinyFish

async def main():
    client = TinyFish()
    session = client.browser.sessions.create(url="https://scrapeme.live/shop")

    async with async_playwright() as p:
        browser = await p.chromium.connect_over_cdp(session.cdp_url)
        page = browser.contexts[0].pages[0]
        await asyncio.sleep(2)
        await page.wait_for_load_state("domcontentloaded")

        products = await page.evaluate("""
            () => [...document.querySelectorAll('.product')].slice(0, 5).map(el => ({
                name: el.querySelector('.woocommerce-loop-product__title')?.textContent,
                price: el.querySelector('.price .amount')?.textContent,
            }))
        """)

        print(json.dumps(products, indent=2))

asyncio.run(main())
Output:
[
  { "name": "Bulbasaur", "price": "£63.00" },
  { "name": "Ivysaur", "price": "£87.00" },
  { "name": "Venusaur", "price": "£105.00" },
  { "name": "Charmander", "price": "£48.00" },
  { "name": "Charmeleon", "price": "£165.00" }
]

Browser Reference

Session parameters, lifecycle, and debugging

Browser Profiles

Standard and stealth browser modes