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}")
import { TinyFish } from "@tiny-fish/sdk";

const client = new TinyFish();
const session = await client.browser.sessions.create({
  url: "https://example.com",
});

console.log(`Session: ${session.session_id}`);
console.log(`CDP URL: ${session.cdp_url}`);
console.log(`Base URL: ${session.base_url}`);
curl -s -X POST https://api.browser.tinyfish.ai \
  -H "X-API-Key: $TINYFISH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'
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())
import { chromium } from "playwright";
import { TinyFish } from "@tiny-fish/sdk";

async function main() {
  const client = new TinyFish();
  const session = await client.browser.sessions.create({
    url: "https://scrapeme.live/shop",
  });

  const browser = await chromium.connectOverCDP(session.cdp_url);
  const page = browser.contexts()[0].pages()[0];

  await page.waitForTimeout(2000);
  await page.waitForLoadState("domcontentloaded");

  const title = await page.title();
  console.log(`Page title: ${title}`);

  await page.screenshot({ path: "shop.png" });
  console.log("Screenshot saved to shop.png");
}

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())
import { chromium } from "playwright";
import { TinyFish } from "@tiny-fish/sdk";

async function main() {
  const client = new TinyFish();
  const session = await client.browser.sessions.create({
    url: "https://scrapeme.live/shop",
  });

  const browser = await chromium.connectOverCDP(session.cdp_url);
  const page = browser.contexts()[0].pages()[0];
  await page.waitForTimeout(2000);
  await page.waitForLoadState("domcontentloaded");

  const 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,
    }))
  );

  console.log(JSON.stringify(products, null, 2));
}

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