ScreenshotNeo

BlogHow-to

How to Get an Element’s Box Model with Puppeteer

Use Puppeteer’s `ElementHandle.boxModel()` to inspect an element’s content, padding, border, and margin quads, with safe null handling and runnable examples.

By the ScreenshotNeo team4 October 20264 min read

Use Puppeteer’s ElementHandle.boxModel() to get an element’s content, padding, border, and margin as coordinate quads. Get an ElementHandle with page.$(), await boxModel(), and handle both a missing selector match and a null model. The method returns null when the element is not part of the layout, such as an element with display: none. See the official boxModel() API.

Runnable example

Install Puppeteer in a Node.js project with npm install puppeteer. This complete script loads a page, finds an element, retrieves its box model, and prints the dimensions and four quads.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.setContent(`
      <style>
        .target {
          width: 200px;
          height: 80px;
          padding: 12px;
          border: 3px solid #333;
          margin: 10px;
        }
      </style>
      <div class="target">Inspect this element</div>
    `);

    const element = await page.$('.target');
    if (!element) {
      throw new Error('No element matched .target');
    }

    const model = await element.boxModel();
    if (!model) {
      throw new Error('The element is not part of the layout');
    }

    console.log('width:', model.width);
    console.log('height:', model.height);
    console.log('content quad:', model.content);
    console.log('padding quad:', model.padding);
    console.log('border quad:', model.border);
    console.log('margin quad:', model.margin);
  } finally {
    await browser.close();
  }
})();

The official BoxModel interface describes each quad as four points with x and y coordinates. Points are sorted clockwise. The model also contains numeric width and height.

Read the box model

Each quad represents a different CSS box layer. A quad’s points let you inspect its corners in page coordinates; they are not simply width and height values.

const model = await element.boxModel();
if (model) {
  const topLeftOfBorder = model.border[0];
  console.log(`border top-left: ${topLeftOfBorder.x}, ${topLeftOfBorder.y}`);

  for (const [name, quad] of Object.entries({
    content: model.content,
    padding: model.padding,
    border: model.border,
    margin: model.margin,
  })) {
    console.log(name, quad.map(({ x, y }) => ({ x, y })));
  }
}
  • content: the content box corners.
  • padding: the padding box corners.
  • border: the border box corners.
  • margin: the margin box corners.
  • width and height: dimensions provided by the returned model.

Handle missing and non-layout elements

There are two separate cases to check. page.$(selector) may return no handle when no element matches. If a handle exists, boxModel() may still return null when that element is not part of the layout.

async function getBoxModel(page, selector) {
  const element = await page.$(selector);
  if (!element) {
    return { error: `No element matched ${selector}` };
  }

  const model = await element.boxModel();
  if (!model) {
    return { error: `Element matched ${selector}, but is not part of the layout` };
  }

  return { model };
}

For example, display: none removes an element from layout, so boxModel() returns null. Check that the selector targets the intended node and that the page has reached the state you want to inspect before interpreting a null result. The API’s documented return type is Promise<BoxModel | null>.

Choose between boxModel() and boundingBox()

Use boxModel() when you need the separate content, padding, border, and margin quads. Use boundingBox() when one bounding rectangle relative to the main frame is enough. boundingBox() also returns null if the element is not part of layout. See the official boundingBox() API.

Need Method Result
Inspect all four CSS box layers and their corners boxModel() BoxModel with four quads, width, and height, or null
Get a single rectangle boundingBox() One bounding rectangle relative to the main frame, or null

Common problems

Symptom Cause What to do
element is null The selector did not match an element when page.$() ran. Check the selector and confirm the page has loaded the expected content.
boxModel() returns null The matched element is not part of layout; display: none is one documented example. Check the element’s layout state and inspect a visible, laid-out target if that is what you need.
A single rectangle does not show padding or margin separately boundingBox() returns a bounding rectangle rather than the four box-layer quads. Use boxModel() for content, padding, border, and margin details.
Code or types do not match the installed Puppeteer version Documentation versions can differ from the version installed in a project. Check the API documentation matching the Puppeteer version in your project.

Reliability and performance notes

Await boxModel() and preserve the null check anywhere layout can vary. If your page changes dynamically, retrieve the model after the page reaches the state you intend to measure; a valid handle alone does not guarantee a non-null layout model. The API documentation does not provide a benchmark or cost figure for this method, so avoid assuming a particular runtime or resource cost.

Or skip the browser setup

If you need a screenshot of a page rather than Puppeteer’s box coordinates, ScreenshotNeo is a website screenshot API and MCP server for developers. Its one-call API returns an image or PDF; it does not return a Puppeteer box model.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation. Cookie banners are accepted like a visitor and removed before the shot, along with known newsletter popups and chat widgets; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers report the page verdict and billing status. Its MCP server lets AI agents use take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.

Sign up free for 1,000 screenshots a month, with no card required.

FAQ

Does boxModel() return CSS pixel values?

The documented result provides numeric width and height and corner points with x and y coordinates. Consult the API documentation for the Puppeteer version installed in your project when you need version-specific details.

Can I use the result to find the border’s top-left point?

Yes. The quad points are sorted clockwise, so model.border[0] is the first point in that ordering. Read its x and y fields.

Does boxModel() capture a screenshot?

No. It returns geometry for the element. Use a screenshot workflow when you need image output.