Skip to content

Dialogs

Handling browser dialog windows in automated sessions.

Updated View as Markdown

What are Chrome dialogs?

A Chrome dialog is any pop-up or modal window that Google Chrome itself creates (not part of a web page) to communicate something to the user or request input. These include:

  • alert() dialogs that display a message with an “OK” button
  • confirm() dialogs that ask for confirmation with “OK” and “Cancel” buttons
  • prompt() dialogs that request text input from the user
  • window.print() dialogs that open the browser’s print interface

These native browser dialogs are different from custom web page modals and require special handling in automation.

Why you can’t interact with them directly

Chrome dialogs block JavaScript execution on the page until they’re dismissed. This means:

  • Automation tools can’t interact with the page while a dialog is open
  • Automation scripts will hang until the dialog is manually dismissed

Preventing Chrome dialogs

The best approach is to prevent these dialogs from appearing by overriding the native dialog functions before any page code runs. Use addInitScript(), which executes code before any page scripts.

Implementation

import { chromium } from "playwright-core";
import { Browsers } from "@agentmq/browsers";

const browsers = new Browsers({ apiKey: process.env.AGENTMQ_TOKEN });
const session = await browsers.sessions.create();

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

// Override dialog functions before page loads
await page.context().addInitScript(() => {
  window.alert = () => {};
  window.confirm = () => true;
  window.prompt = () => '';
});

// Now navigate to your target page
await page.goto("https://example.com");

// Dialogs should now be prevented

await page.close();
await browser.close();
from agentmq.browsers import Browsers
from playwright.sync_api import sync_playwright
import os

browsers = Browsers(api_key=os.environ["AGENTMQ_TOKEN"])
session = browsers.sessions.create()

with sync_playwright() as playwright:
    browser = playwright.chromium.connect_over_cdp(session.connect_url)
    context = browser.contexts[0]
    page = context.pages[0]

    # Override dialog functions before page loads
    context.add_init_script("""
        window.alert = () => {};
        window.confirm = () => true;
        window.prompt = () => '';
    """)

    # Now navigate to your target page
    page.goto("https://example.com")

    # Dialogs should now be prevented

    page.close()
    browser.close()

Customizing dialog behavior

You can customize the return values based on your automation needs:

// Always reject confirmations
window.confirm = () => false;

// Return a specific value for prompts
window.prompt = () => 'my custom input';

// Log when dialogs would have appeared
window.alert = (message) => console.log('Alert prevented:', message);

Handling PDF dialogs

PDF dialogs present unique challenges because PDFs can be generated and displayed in different ways. You’ll encounter two common scenarios:

Scenario 1: PDF opens in the current tab

When a PDF replaces the current page content, you need to capture it differently:

import { chromium } from "playwright-core";
import { Browsers } from "@agentmq/browsers";
import fs from 'fs/promises';

const browsers = new Browsers({ apiKey: process.env.AGENTMQ_TOKEN });
const session = await browsers.sessions.create();

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

let savedPdfPath: string | null = null;

// Route PDF requests to capture them
await context.route('**/*.pdf', async (route) => {
  const resp = await route.fetch();
  const contentType = (resp.headers()['content-type'] ?? '').toLowerCase();

  if (contentType.includes('application/pdf')) {
    const url = route.request().url();
    const name = new URL(url).pathname.split('/').pop() || 'document.pdf';
    const outputPath = `captured-${Date.now()}-${name}`;
    const buffer = await resp.body();

    await fs.writeFile(outputPath, buffer);
    console.log('Saved PDF (network):', outputPath, 'from', url);
    savedPdfPath = outputPath;
  }

  await route.fulfill({ response: resp });
});

// Override print dialog
await context.addInitScript(() => {
  window.print = () => {};

  // Also capture client-side blobs as fallback
  const origCreate = URL.createObjectURL;
  (window as any).__pdfBlobs = [];
  URL.createObjectURL = function (blob: Blob) {
    try {
      if ((blob as any)?.type?.toLowerCase?.().includes('application/pdf')) {
        (window as any).__pdfBlobs.push(blob);
      }
    } catch {}
    return origCreate.apply(this, arguments);
  };
});

await page.goto("https://dialogue-interaction.vercel.app/");

// Trigger PDF generation
await page.click("#open-pdf");

// If network capture didn't work, try blob capture
if (!savedPdfPath) {
  const arrays = await page.evaluate(async () => {
    const blobs: Blob[] = (window as any).__pdfBlobs || [];
    const bufs = await Promise.all(blobs.map(b => b.arrayBuffer()));
    return bufs.map(ab => Array.from(new Uint8Array(ab)));
  });

  if (arrays.length) {
    const buf = Buffer.from(Uint8Array.from(arrays[0]));
    const outputPath = `captured-blob-${Date.now()}.pdf`;
    await fs.writeFile(outputPath, buf);
    console.log('Saved PDF (blob):', outputPath);
    savedPdfPath = outputPath;
  }
}

await page.close();
await browser.close();
from playwright.sync_api import sync_playwright
from agentmq.browsers import Browsers
import time
import os

browsers = Browsers(api_key=os.environ["AGENTMQ_TOKEN"])
session = browsers.sessions.create()

saved_pdf_path = None

with sync_playwright() as playwright:
    browser = playwright.chromium.connect_over_cdp(session.connect_url)
    context = browser.contexts[0]
    page = context.pages[0]

    # Route PDF requests to capture them
    def handle_route(route):
        nonlocal saved_pdf_path
        response = route.fetch()
        content_type = (response.headers.get('content-type', '')).lower()

        if 'application/pdf' in content_type:
            url = route.request.url
            name = url.split('/')[-1] or 'document.pdf'
            output_path = f"captured-{int(time.time() * 1000)}-{name}"
            buffer = response.body()

            with open(output_path, 'wb') as f:
                f.write(buffer)
            print(f"Saved PDF (network): {output_path} from {url}")
            saved_pdf_path = output_path

        route.fulfill(response=response)

    context.route('**/*.pdf', handle_route)

    # Override print dialog and capture blobs
    context.add_init_script("""
        window.print = () => {};

        const origCreate = URL.createObjectURL;
        window.__pdfBlobs = [];
        URL.createObjectURL = function(blob) {
            try {
                if (blob?.type?.toLowerCase?.().includes('application/pdf')) {
                    window.__pdfBlobs.push(blob);
                }
            } catch {}
            return origCreate.apply(this, arguments);
        };
    """)

    page.goto("https://dialogue-interaction.vercel.app/")

    # Trigger PDF generation
    page.click("#open-pdf")

    # If network capture didn't work, try blob capture
    if not saved_pdf_path:
        arrays = page.evaluate("""
            async () => {
                const blobs = window.__pdfBlobs || [];
                const bufs = await Promise.all(blobs.map(b => b.arrayBuffer()));
                return bufs.map(ab => Array.from(new Uint8Array(ab)));
            }
        """)

        if arrays:
            pdf_data = bytes(arrays[0])
            output_path = f"captured-blob-{int(time.time() * 1000)}.pdf"
            with open(output_path, 'wb') as f:
                f.write(pdf_data)
            print(f"Saved PDF (blob): {output_path}")
            saved_pdf_path = output_path

    browser.close()

Scenario 2: PDF opens in a new tab

When a PDF is generated client-side and opens in a new tab, you can capture the PDF blob before it’s displayed:

import { chromium } from "playwright-core";
import { Browsers } from "@agentmq/browsers";
import fs from 'fs/promises';

const browsers = new Browsers({ apiKey: process.env.AGENTMQ_TOKEN });
const session = await browsers.sessions.create();

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

// Prevent print dialog and capture PDF blobs
await context.addInitScript(() => {
  // Don't let native print dialog block
  window.print = () => {};

  // Capture client-side generated PDF blobs
  const origCreate = URL.createObjectURL;
  (window as any).__pdfBlobs = [];
  URL.createObjectURL = function (blob: Blob) {
    try {
      if ((blob as any)?.type?.toLowerCase?.().includes('application/pdf')) {
        (window as any).__pdfBlobs.push(blob);
      }
    } catch {}
    return origCreate.apply(this, arguments);
  };
});

await page.goto("http://pdfmake.org/playground.html");

// Trigger PDF generation by clicking the print button
await page.click("#printThis li:nth-child(2)");

// Wait for PDF to be generated
await page.waitForTimeout(1000);

// Extract and save the PDF
const arrays = await page.evaluate(async () => {
  const blobs: Blob[] = (window as any).__pdfBlobs || [];
  const bufs = await Promise.all(blobs.map(b => b.arrayBuffer()));
  return bufs.map(ab => Array.from(new Uint8Array(ab)));
});

if (arrays.length) {
  const buf = Buffer.from(Uint8Array.from(arrays[0]));
  const outputPath = `captured-blob-${Date.now()}.pdf`;
  await fs.writeFile(outputPath, buf);
  console.log('Saved PDF (blob):', outputPath);
}

await page.close();
await browser.close();
from playwright.sync_api import sync_playwright
from agentmq.browsers import Browsers
import time
import os

browsers = Browsers(api_key=os.environ["AGENTMQ_TOKEN"])
session = browsers.sessions.create()

with sync_playwright() as playwright:
    browser = playwright.chromium.connect_over_cdp(session.connect_url)
    context = browser.contexts[0]
    page = context.pages[0]

    # Prevent print dialog and capture PDF blobs
    context.add_init_script("""
        window.print = () => {};

        const origCreate = URL.createObjectURL;
        window.__pdfBlobs = [];
        URL.createObjectURL = function(blob) {
            try {
                if (blob?.type?.toLowerCase?.().includes('application/pdf')) {
                    window.__pdfBlobs.push(blob);
                }
            } catch {}
            return origCreate.apply(this, arguments);
        };
    """)

    page.goto("http://pdfmake.org/playground.html")

    # Trigger PDF generation by clicking the print button
    page.click("#printThis li:nth-child(2)")
    page.wait_for_timeout(1000)

    # Extract and save the PDF
    arrays = page.evaluate("""
        async () => {
            const blobs = window.__pdfBlobs || [];
            const bufs = await Promise.all(blobs.map(b => b.arrayBuffer()));
            return bufs.map(ab => Array.from(new Uint8Array(ab)));
        }
    """)

    if arrays:
        pdf_data = bytes(arrays[0])
        output_path = f"captured-blob-{int(time.time() * 1000)}.pdf"
        with open(output_path, 'wb') as f:
            f.write(pdf_data)
        print(f"Saved PDF (blob): {output_path}")

    browser.close()

How PDF capture works

Both scenarios use a combination of techniques:

  1. Override window.print() - Prevents the native print dialog from blocking automation
  2. Intercept URL.createObjectURL() - Captures client-side generated PDF blobs before they’re displayed
  3. Route network requests (Scenario 1) - Intercepts PDF files loaded from the network

The key difference:

  • Scenario 1: PDF might be fetched from the network or generated, and the print dialog appears in the current tab
  • Scenario 2: PDF is generated client-side and stored in a blob, opened in a new tab where the print dialog appears
Navigation

Type to search…

↑↓ navigate↵ selectEsc close