Skip to main content
Take screenshots of the mobile browser viewport to capture visual state, debug issues, or document test results.

Method

page.screenshot()

Takes a screenshot of the page viewport.
page.screenshot(width?: number, height?: number, quality?: number): Promise<string | undefined>
Parameters:
  • width (optional): Viewport width in pixels, 0 for auto (default: 0)
  • height (optional): Viewport height in pixels, 0 for auto (default: 0)
  • quality (optional): JPEG quality from 0 to 1 (default: 0.8)
Returns: Promise<string | undefined> - Base64-encoded image data (JPEG format) Examples:
// Default screenshot (auto size, 0.8 quality)
const screenshot = await page.screenshot()

// Custom size
const screenshot = await page.screenshot(1920, 1080)

// High quality
const screenshot = await page.screenshot(0, 0, 1.0)

// Specific size and quality
const screenshot = await page.screenshot(800, 600, 0.9)

Complete examples

Basic screenshot

await page.goto('https://example.com')
await page.waitForSelector('#main-content')

const screenshot = await page.screenshot()

if (screenshot) {
  console.log('Screenshot captured')
  // Screenshot is base64-encoded JPEG data
} else {
  console.log('Screenshot failed')
}

Save screenshot to file

import fs from 'fs/promises'

async function captureAndSave(page, filename) {
  const screenshot = await page.screenshot()

  if (screenshot) {
    // Remove base64 prefix if present
    const base64Data = screenshot.replace(/^data:image\/jpeg;base64,/, '')

    // Convert to buffer and save
    const buffer = Buffer.from(base64Data, 'base64')
    await fs.writeFile(filename, buffer)

    console.log('Screenshot saved to', filename)
  }
}

await page.goto('https://example.com')
await captureAndSave(page, 'page.jpg')

Screenshot with custom dimensions

async function captureCustomSize(page) {
  // Capture at different sizes
  const mobile = await page.screenshot(375, 812, 0.9)   // iPhone size
  const tablet = await page.screenshot(768, 1024, 0.9)  // iPad size
  const desktop = await page.screenshot(1920, 1080, 0.9) // Desktop size

  return { mobile, tablet, desktop }
}

await page.goto('https://example.com')
const screenshots = await captureCustomSize(page)

Screenshot after interaction

await page.goto('https://example.com')

// Capture before clicking
const before = await page.screenshot()

// Interact with page
await page.click('#toggle-button')
await page.waitForSelector('.expanded-content')

// Capture after clicking
const after = await page.screenshot()

// Save both for comparison
await saveScreenshot(before, 'before.jpg')
await saveScreenshot(after, 'after.jpg')

Screenshot for test evidence

async function runTest(page, testName) {
  try {
    await page.goto('https://example.com/feature')
    await page.click('#action-button')
    await page.waitForSelector('.success')

    // Capture success state
    const screenshot = await page.screenshot()
    await saveScreenshot(screenshot, `${testName}-success.jpg`)

    console.log(`✓ Test "${testName}" passed`)
    return true

  } catch (error) {
    // Capture failure state
    const screenshot = await page.screenshot()
    await saveScreenshot(screenshot, `${testName}-failure.jpg`)

    console.error(`✗ Test "${testName}" failed:`, error.message)
    return false
  }
}

const passed = await runTest(page, 'checkout-flow')

Screenshot sequence

async function captureSequence(page, actions) {
  const screenshots = []

  for (let i = 0; i < actions.length; i++) {
    const action = actions[i]

    // Perform action
    await action(page)

    // Wait a bit for UI to settle
    await new Promise(resolve => setTimeout(resolve, 500))

    // Capture screenshot
    const screenshot = await page.screenshot()

    screenshots.push({
      step: i + 1,
      name: action.name,
      image: screenshot
    })

    console.log(`Captured step ${i + 1}: ${action.name}`)
  }

  return screenshots
}

const sequence = await captureSequence(page, [
  { name: 'Homepage', action: (p) => p.goto('https://example.com') },
  { name: 'Click login', action: (p) => p.click('#login') },
  { name: 'Enter email', action: (p) => p.input('#email', 'user@example.com') },
  { name: 'Enter password', action: (p) => p.input('#password', 'pass') },
  { name: 'Submit form', action: (p) => p.click('#submit') }
])

// Save sequence
sequence.forEach((step, i) => {
  saveScreenshot(step.image, `step-${i + 1}-${step.name}.jpg`)
})

Compare screenshots

import { createHash } from 'crypto'

function getImageHash(base64Image) {
  return createHash('md5').update(base64Image).digest('hex')
}

async function hasPageChanged(page, previousScreenshot) {
  const currentScreenshot = await page.screenshot()

  if (!currentScreenshot) return false

  const previousHash = getImageHash(previousScreenshot)
  const currentHash = getImageHash(currentScreenshot)

  return previousHash !== currentHash
}

// Capture initial state
const initial = await page.screenshot()

// Do something
await page.click('#refresh-button')
await new Promise(resolve => setTimeout(resolve, 2000))

// Check if page changed
const changed = await hasPageChanged(page, initial)
console.log('Page changed:', changed)

Screenshot with different qualities

async function compareQualities(page) {
  const qualities = [0.3, 0.5, 0.7, 0.9, 1.0]

  for (const quality of qualities) {
    const screenshot = await page.screenshot(0, 0, quality)

    if (screenshot) {
      const size = Buffer.from(screenshot, 'base64').length
      console.log(`Quality ${quality}: ${(size / 1024).toFixed(2)} KB`)

      await saveScreenshot(screenshot, `quality-${quality}.jpg`)
    }
  }
}

await page.goto('https://example.com')
await compareQualities(page)

Screenshot on error

async function automationWithErrorCapture(page) {
  try {
    await page.goto('https://example.com')
    await page.click('#button')
    await page.waitForSelector('.result', { timeout: 5000 })

  } catch (error) {
    console.error('Error occurred:', error.message)

    // Capture screenshot for debugging
    const screenshot = await page.screenshot()

    if (screenshot) {
      const timestamp = Date.now()
      await saveScreenshot(screenshot, `error-${timestamp}.jpg`)
      console.log('Error screenshot saved')
    }

    throw error
  }
}

Visual regression testing

async function captureBaseline(page, name) {
  await page.goto('https://example.com')
  const screenshot = await page.screenshot()
  await saveScreenshot(screenshot, `baseline-${name}.jpg`)
  return screenshot
}

async function compareWithBaseline(page, name, baseline) {
  const current = await page.screenshot()

  if (!current) {
    throw new Error('Failed to capture screenshot')
  }

  const baselineHash = getImageHash(baseline)
  const currentHash = getImageHash(current)

  if (baselineHash !== currentHash) {
    await saveScreenshot(current, `diff-${name}.jpg`)
    throw new Error('Visual regression detected!')
  }

  console.log('Visual test passed')
}

// Capture baseline
const baseline = await captureBaseline(page, 'homepage')

// Later, compare
await page.goto('https://example.com')
await compareWithBaseline(page, 'homepage', baseline)

Best practices

Always wait for important content before taking screenshots:
await page.goto('https://example.com')
await page.waitForSelector('.main-content')
await new Promise(resolve => setTimeout(resolve, 500)) // Let animations finish
const screenshot = await page.screenshot()
Balance quality and file size:
// High quality for reports (larger files)
const report = await page.screenshot(0, 0, 1.0)

// Medium quality for testing (smaller files)
const test = await page.screenshot(0, 0, 0.7)
Check if screenshot succeeded:
const screenshot = await page.screenshot()

if (!screenshot) {
  console.error('Screenshot failed')
  // Handle failure
}
Use descriptive filenames and organize by test/feature:
const timestamp = new Date().toISOString().replace(/:/g, '-')
const filename = `${testName}-${timestamp}.jpg`
await saveScreenshot(screenshot, `screenshots/${testName}/${filename}`)